mirror of
https://github.com/bitsocialnet/5chan.git
synced 2026-08-03 07:41:04 +02:00
merge: sync codex/fix/flash-no-catalog with master
This commit is contained in:
@@ -444,6 +444,7 @@ describe('PostForm', () => {
|
|||||||
testState.directories = [
|
testState.directories = [
|
||||||
{ address: 'music-posting.eth', features: {}, title: '/mu/ - Music' },
|
{ address: 'music-posting.eth', features: {}, title: '/mu/ - Music' },
|
||||||
{ address: 'politically-incorrect.bso', directoryCode: 'pol', features: { hasFlags: true }, title: '/pol/ - Politically Incorrect' },
|
{ address: 'politically-incorrect.bso', directoryCode: 'pol', features: { hasFlags: true }, title: '/pol/ - Politically Incorrect' },
|
||||||
|
{ address: 'sports-posting.bso', directoryCode: 'sp', features: { hasFlags: true }, title: '/sp/ - Sports' },
|
||||||
{ address: 'random-nsfw.bso', features: {}, title: '/b/ - Random' },
|
{ address: 'random-nsfw.bso', features: {}, title: '/b/ - Random' },
|
||||||
{
|
{
|
||||||
address: 'flash-posting.bso',
|
address: 'flash-posting.bso',
|
||||||
@@ -699,6 +700,30 @@ describe('PostForm', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('publishes geographic location on /sp/ without showing a flag field', async () => {
|
||||||
|
testState.resolvedCommunityAddress = 'sports-posting.bso';
|
||||||
|
|
||||||
|
await renderPostForm('/sp');
|
||||||
|
await clickByText(container, 'start_new_thread');
|
||||||
|
|
||||||
|
const table = container.querySelector('table');
|
||||||
|
const flagSelect = table?.querySelector<HTMLSelectElement>('select[aria-label="flag"]');
|
||||||
|
const textarea = table?.querySelector<HTMLTextAreaElement>('textarea');
|
||||||
|
|
||||||
|
expect(flagSelect).toBeNull();
|
||||||
|
|
||||||
|
await dispatchInput(textarea as HTMLTextAreaElement, 'sports post');
|
||||||
|
await clickByText(table as HTMLTableElement, 'post');
|
||||||
|
|
||||||
|
expect(testState.publishPostMock).toHaveBeenCalledWith({
|
||||||
|
content: 'sports post',
|
||||||
|
challengeRequest: {
|
||||||
|
challengeAnswers: ['bitsocial-flags:5chan:flag:country:auto'],
|
||||||
|
},
|
||||||
|
flairs: [{ type: 'country', code: 'auto', text: 'flag:country:auto' }],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it('publishes selected political flags from the post form', async () => {
|
it('publishes selected political flags from the post form', async () => {
|
||||||
testState.resolvedCommunityAddress = 'politically-incorrect.bso';
|
testState.resolvedCommunityAddress = 'politically-incorrect.bso';
|
||||||
|
|
||||||
|
|||||||
@@ -391,7 +391,7 @@ const PostFormFields = ({
|
|||||||
<tr>
|
<tr>
|
||||||
<td>{t('tag')}</td>
|
<td>{t('tag')}</td>
|
||||||
<td>
|
<td>
|
||||||
<select name='flashTag' aria-label={t('tag')} ref={flashTagRef} defaultValue=''>
|
<select name='flashTag' aria-label={t('tag')} className={styles.flagSelector} ref={flashTagRef} defaultValue=''>
|
||||||
<option value=''>{t('choose_one')}</option>
|
<option value=''>{t('choose_one')}</option>
|
||||||
{flashTagOptions.map((option) => (
|
{flashTagOptions.map((option) => (
|
||||||
<option key={option.value} value={option.value}>
|
<option key={option.value} value={option.value}>
|
||||||
|
|||||||
@@ -340,6 +340,18 @@ describe('ReplyModal', () => {
|
|||||||
features: { hasFlags: true },
|
features: { hasFlags: true },
|
||||||
title: '/bant/ - International/Random',
|
title: '/bant/ - International/Random',
|
||||||
},
|
},
|
||||||
|
'international-sfw.bso': {
|
||||||
|
address: 'international-sfw.bso',
|
||||||
|
directoryCode: 'int',
|
||||||
|
features: { hasFlags: true },
|
||||||
|
title: '/int/ - International',
|
||||||
|
},
|
||||||
|
'sports-posting.bso': {
|
||||||
|
address: 'sports-posting.bso',
|
||||||
|
directoryCode: 'sp',
|
||||||
|
features: { hasFlags: true },
|
||||||
|
title: '/sp/ - Sports',
|
||||||
|
},
|
||||||
'random-nsfw.bso': {
|
'random-nsfw.bso': {
|
||||||
address: 'random-nsfw.bso',
|
address: 'random-nsfw.bso',
|
||||||
features: {},
|
features: {},
|
||||||
@@ -494,8 +506,12 @@ describe('ReplyModal', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('publishes geographic location on /bant/ without showing a flag selector', async () => {
|
it.each([
|
||||||
await renderReplyModal('/bant/thread/post-1', 'international-nsfw.bso');
|
{ boardPath: '/bant/thread/post-1', communityAddress: 'international-nsfw.bso' },
|
||||||
|
{ boardPath: '/int/thread/post-1', communityAddress: 'international-sfw.bso' },
|
||||||
|
{ boardPath: '/sp/thread/post-1', communityAddress: 'sports-posting.bso' },
|
||||||
|
])('publishes geographic location on country-only boards without showing a flag selector', async ({ boardPath, communityAddress }) => {
|
||||||
|
await renderReplyModal(boardPath, communityAddress);
|
||||||
|
|
||||||
expect(container.querySelector<HTMLSelectElement>('select[aria-label="flag"]')).toBeNull();
|
expect(container.querySelector<HTMLSelectElement>('select[aria-label="flag"]')).toBeNull();
|
||||||
|
|
||||||
|
|||||||
+67
@@ -256,6 +256,73 @@ describe('P2PStatsSettings', () => {
|
|||||||
expect(fetchMock).toHaveBeenCalledWith('https://free.freeipapi.com/api/json/91.234.199.189', expect.objectContaining({ signal: expect.any(AbortSignal) }));
|
expect(fetchMock).toHaveBeenCalledWith('https://free.freeipapi.com/api/json/91.234.199.189', expect.objectContaining({ signal: expect.any(AbortSignal) }));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('shows peer country flags for DNS6 relay hostnames with embedded IPv6 addresses', async () => {
|
||||||
|
const fetchMock = vi.fn(async (url: string | URL | Request) => {
|
||||||
|
const requestUrl = String(url);
|
||||||
|
if (requestUrl === 'https://free.freeipapi.com/api/json/2a11%3A6100%3A0%3A5e9f%3A%3A0') {
|
||||||
|
return {
|
||||||
|
ok: true,
|
||||||
|
json: async () => ({
|
||||||
|
cityName: 'Reykjavik',
|
||||||
|
countryCode: 'IS',
|
||||||
|
ipAddress: '2a11:6100:0:5e9f::0',
|
||||||
|
latitude: 64.1466,
|
||||||
|
longitude: -21.9426,
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
ok: true,
|
||||||
|
json: async () => ({ country: 'US', ip: '147.75.84.175' }),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
vi.stubGlobal('fetch', fetchMock);
|
||||||
|
testState.account = {
|
||||||
|
...testState.account,
|
||||||
|
pkcOptions: {
|
||||||
|
libp2pJsClientsOptions: [{ key: 'libp2pjs' }],
|
||||||
|
},
|
||||||
|
pkc: {
|
||||||
|
clients: {
|
||||||
|
libp2pJsClients: {
|
||||||
|
libp2pjs: {
|
||||||
|
key: 'libp2pjs',
|
||||||
|
_helia: {
|
||||||
|
libp2p: {
|
||||||
|
getConnections: () => [
|
||||||
|
{
|
||||||
|
remoteAddr: {
|
||||||
|
toString: () => '/dns6/2a11-6100-0-5e9f--0.k51qzi5uqu5djg5pdoi9a98.example/tcp/443/ws/p2p/relay-peer/p2p-circuit/p2p/12D3KooWIPv6Peer',
|
||||||
|
},
|
||||||
|
remotePeer: { toString: () => '12D3KooWIPv6Peer' },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
getMultiaddrs: () => ['/ip4/147.75.84.175/tcp/4001/ws'],
|
||||||
|
getPeers: () => ['12D3KooWIPv6Peer'],
|
||||||
|
peerId: { toString: () => 'self-peer' },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
await renderSettings(false);
|
||||||
|
await act(async () => {
|
||||||
|
await Promise.resolve();
|
||||||
|
await Promise.resolve();
|
||||||
|
});
|
||||||
|
|
||||||
|
const connectedPeers = container.querySelector('[data-testid="connected-peers"]');
|
||||||
|
expect(connectedPeers?.textContent).toContain('WebSocket through relay');
|
||||||
|
expect(connectedPeers?.querySelector('img[aria-label="Iceland"]')).not.toBeNull();
|
||||||
|
expect(fetchMock).toHaveBeenCalledWith(
|
||||||
|
'https://free.freeipapi.com/api/json/2a11%3A6100%3A0%3A5e9f%3A%3A0',
|
||||||
|
expect.objectContaining({ signal: expect.any(AbortSignal) }),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
it('shows the own IP flag and a red precise map marker when leeching', async () => {
|
it('shows the own IP flag and a red precise map marker when leeching', async () => {
|
||||||
const fetchMock = vi.fn(async (url: string | URL | Request) => {
|
const fetchMock = vi.fn(async (url: string | URL | Request) => {
|
||||||
const requestUrl = String(url);
|
const requestUrl = String(url);
|
||||||
|
|||||||
@@ -17,30 +17,34 @@ describe('comment-flag-selection', () => {
|
|||||||
expect(hasCommentFlagsForDirectory({ features: { hasFlags: true }, title: '/pol/ - Politically Incorrect' })).toBe(true);
|
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(
|
expect(
|
||||||
getCommentFlagOptionsForDirectory({
|
getCommentFlagOptionsForDirectory({
|
||||||
directoryCode: 'int',
|
directoryCode: 'fit',
|
||||||
features: { hasFlags: true },
|
features: { hasFlags: true },
|
||||||
title: '/int/ - International',
|
title: '/fit/ - Fitness',
|
||||||
}),
|
}),
|
||||||
).toEqual([{ label: 'Geographic Location', value: 'country:auto' }]);
|
).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(
|
expect(
|
||||||
getCommentFlagOptionsForDirectory({
|
getCommentFlagOptionsForDirectory({
|
||||||
directoryCode: 'bant',
|
directoryCode,
|
||||||
features: { hasFlags: true },
|
features: { hasFlags: true },
|
||||||
title: '/bant/ - International/Random',
|
title,
|
||||||
}),
|
}),
|
||||||
).toEqual([]);
|
).toEqual([]);
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
getCommentFlagPublishOptionsForDirectory({
|
getCommentFlagPublishOptionsForDirectory({
|
||||||
directoryCode: 'bant',
|
directoryCode,
|
||||||
features: { hasFlags: true },
|
features: { hasFlags: true },
|
||||||
title: '/bant/ - International/Random',
|
title,
|
||||||
}),
|
}),
|
||||||
).toEqual({
|
).toEqual({
|
||||||
challengeRequest: {
|
challengeRequest: {
|
||||||
|
|||||||
@@ -37,6 +37,13 @@ describe('extractIpv6FromAddress', () => {
|
|||||||
expect(extractIpv6FromAddress('/ip6/2001:4860:4860::8888/tcp/4001/ws')).toBe('2001:4860:4860::8888');
|
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');
|
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', () => {
|
describe('isPrivateOrReservedIpv4', () => {
|
||||||
@@ -261,6 +268,31 @@ describe('fetchPeerMapLocation', () => {
|
|||||||
|
|
||||||
vi.unstubAllGlobals();
|
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', () => {
|
describe('getApproximateCountryCode', () => {
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ const NO_FLAG_OPTION: CommentFlagSelectOption = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/** Boards that always publish geographic location without showing a flag selector. */
|
/** 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 getDirectoryCode = (directory: Pick<DirectoryCommunity, 'directoryCode' | 'title'> | undefined): string | undefined => {
|
||||||
const directoryCode = directory?.directoryCode?.trim().toLowerCase();
|
const directoryCode = directory?.directoryCode?.trim().toLowerCase();
|
||||||
|
|||||||
+11
-1
@@ -284,7 +284,17 @@ export const extractIpv4FromAddress = (address: string): string | null => {
|
|||||||
|
|
||||||
export const extractIpv6FromAddress = (address: string): string | null => {
|
export const extractIpv6FromAddress = (address: string): string | null => {
|
||||||
const direct = /\/ip6\/([^/]+)/.exec(address);
|
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 => {
|
const parseOctets = (ip: string): number[] | null => {
|
||||||
|
|||||||
Reference in New Issue
Block a user