Public-release prep: ELv2 license, README/CLA/NOTICE, SSRF safeFetch, identifier genericization, export tooling
This commit is contained in:
@@ -185,8 +185,8 @@ describe('formatDmPreview', () => {
|
||||
|
||||
const actor: User = {
|
||||
id: 'U1',
|
||||
username: 'jannis',
|
||||
displayName: 'Jannis',
|
||||
username: 'heidi',
|
||||
displayName: 'Heidi',
|
||||
avatarColor: 'mint',
|
||||
avatar: null,
|
||||
bio: null,
|
||||
@@ -217,7 +217,7 @@ describe('formatDmSidebarPreview — name_changed system message', () => {
|
||||
content: JSON.stringify({ event: 'name_changed', oldName: null, newName: 'Cool Group' }),
|
||||
createdAt: 1,
|
||||
});
|
||||
expect(formatDmSidebarPreview(dm, { id: 'OTHER', username: 'other' })).toBe('Jannis renamed the group');
|
||||
expect(formatDmSidebarPreview(dm, { id: 'OTHER', username: 'other' })).toBe('Heidi renamed the group');
|
||||
});
|
||||
|
||||
it('newName=null (cleared) → "<actor> cleared the group name"', () => {
|
||||
@@ -227,7 +227,7 @@ describe('formatDmSidebarPreview — name_changed system message', () => {
|
||||
content: JSON.stringify({ event: 'name_changed', oldName: 'Old', newName: null }),
|
||||
createdAt: 1,
|
||||
});
|
||||
expect(formatDmSidebarPreview(dm, { id: 'OTHER', username: 'other' })).toBe('Jannis cleared the group name');
|
||||
expect(formatDmSidebarPreview(dm, { id: 'OTHER', username: 'other' })).toBe('Heidi cleared the group name');
|
||||
});
|
||||
|
||||
it('unresolvable actor → "Unknown renamed the group"', () => {
|
||||
@@ -391,7 +391,7 @@ describe('formatDmSidebarPreview — icon_changed system message', () => {
|
||||
content: JSON.stringify({ event: 'icon_changed' }),
|
||||
createdAt: 1,
|
||||
});
|
||||
expect(formatDmSidebarPreview(dm, { id: 'OTHER', username: 'other' })).toBe('Jannis updated the group icon');
|
||||
expect(formatDmSidebarPreview(dm, { id: 'OTHER', username: 'other' })).toBe('Heidi updated the group icon');
|
||||
});
|
||||
|
||||
it('unresolvable actor → "Unknown updated the group icon"', () => {
|
||||
|
||||
@@ -299,7 +299,7 @@ export function formatDmHeaderName(dm: DmChannel, currentUser: AuthLike): string
|
||||
*
|
||||
* The unnamed-group case intentionally collapses to a generic noun: the
|
||||
* joined-names form is unreadable as a one-line placeholder once a group
|
||||
* has 4+ members ("Message #Test, Nova, youruser, Nova" runs off-screen
|
||||
* has 4+ members ("Message #Test, Nova, erin, Nova" runs off-screen
|
||||
* and obscures the actual call-to-action).
|
||||
*/
|
||||
export function formatDmInputLabel(dm: DmChannel, currentUser: AuthLike): string {
|
||||
|
||||
@@ -16,7 +16,7 @@ describe('normalizeOriginToHost', () => {
|
||||
it('extracts host from full URLs', () => {
|
||||
expect(normalizeOriginToHost('https://nova.ddns.net')).toBe('nova.ddns.net');
|
||||
expect(normalizeOriginToHost('http://localhost:3000')).toBe('localhost:3000');
|
||||
expect(normalizeOriginToHost('https://orbit.example.com:8443/path')).toBe('orbit.example.com:8443');
|
||||
expect(normalizeOriginToHost('https://orbit.ddns.net:8443/path')).toBe('orbit.ddns.net:8443');
|
||||
});
|
||||
|
||||
it('returns bare-domain inputs unchanged', () => {
|
||||
@@ -47,12 +47,12 @@ describe('canonicalUserKey', () => {
|
||||
it('produces the same key for stubs of the same person across instances', () => {
|
||||
const fromOrbit = canonicalUserKey({
|
||||
id: 'orbitLocalId',
|
||||
homeUserId: 'nova-axel',
|
||||
homeUserId: 'nova-frank',
|
||||
homeInstance: 'nova.ddns.net',
|
||||
});
|
||||
const fromAnotherPeer = canonicalUserKey({
|
||||
id: 'otherPeerLocalId',
|
||||
homeUserId: 'nova-axel',
|
||||
homeUserId: 'nova-frank',
|
||||
homeInstance: 'nova.ddns.net',
|
||||
});
|
||||
expect(fromOrbit).toBe(fromAnotherPeer);
|
||||
@@ -109,7 +109,7 @@ describe('isDeliveryFromHome', () => {
|
||||
)).toBe(true);
|
||||
});
|
||||
|
||||
it('rejects sibling-stub deliveries (orbit delivering Axel whose home is nova)', () => {
|
||||
it('rejects sibling-stub deliveries (orbit delivering Frank whose home is nova)', () => {
|
||||
expect(isDeliveryFromHome(
|
||||
{ homeInstance: 'nova.ddns.net' },
|
||||
'https://orbit.ddns.net',
|
||||
@@ -141,16 +141,16 @@ describe('isFederationGlobeApplicable', () => {
|
||||
});
|
||||
|
||||
it('returns false for purely-local users (no @domain in username)', () => {
|
||||
expect(isFederationGlobeApplicable({ username: 'axel' })).toBe(false);
|
||||
expect(isFederationGlobeApplicable({ username: 'youruser' })).toBe(false);
|
||||
expect(isFederationGlobeApplicable({ username: 'frank' })).toBe(false);
|
||||
expect(isFederationGlobeApplicable({ username: 'erin' })).toBe(false);
|
||||
});
|
||||
|
||||
it('returns false when the username domain matches our own host (the load-bearing case)', () => {
|
||||
// Logged in to nova; viewing orbit-stub of Axel whose username is "axel@nova.ddns.net".
|
||||
expect(isFederationGlobeApplicable({ username: 'axel@nova.ddns.net' })).toBe(false);
|
||||
// Logged in to nova; viewing orbit-stub of Frank whose username is "frank@nova.ddns.net".
|
||||
expect(isFederationGlobeApplicable({ username: 'frank@nova.ddns.net' })).toBe(false);
|
||||
});
|
||||
|
||||
it('returns true for genuinely remote users', () => {
|
||||
expect(isFederationGlobeApplicable({ username: 'jannis@orbit.ddns.net' })).toBe(true);
|
||||
expect(isFederationGlobeApplicable({ username: 'heidi@orbit.ddns.net' })).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -2,8 +2,8 @@ import type { User } from '@backspace/shared';
|
||||
|
||||
/**
|
||||
* Splits a potentially federated username into base name and domain.
|
||||
* "youruser@nova.ddns.net" → { baseName: "youruser", domain: "nova.ddns.net" }
|
||||
* "youruser" → { baseName: "youruser", domain: null }
|
||||
* "erin@nova.ddns.net" → { baseName: "erin", domain: "nova.ddns.net" }
|
||||
* "erin" → { baseName: "erin", domain: null }
|
||||
*/
|
||||
export function parseFederatedUsername(username: string): { baseName: string; domain: string | null } {
|
||||
const atIndex = username.indexOf('@');
|
||||
@@ -42,7 +42,7 @@ export function isSelf(
|
||||
// Replicated user: homeInstance matches our origin
|
||||
if (!user.homeInstance) return false;
|
||||
if (user.homeInstance !== window.location.host) return false;
|
||||
// Username: "youruser" or "youruser@nova.ddns.net" → base must match
|
||||
// Username: "erin" or "erin@nova.ddns.net" → base must match
|
||||
const { baseName } = parseFederatedUsername(user.username);
|
||||
const { baseName: homeBase } = parseFederatedUsername(homeUser.username);
|
||||
return baseName === homeBase;
|
||||
@@ -150,7 +150,7 @@ export function isDeliveryFromHome(
|
||||
*
|
||||
* True iff the user is genuinely remote: their username carries an `@domain`
|
||||
* suffix AND that domain is NOT our own host. Catches the bug where a stub
|
||||
* delivered by a sibling instance (e.g. orbit-side `axel@nova.ddns.net`
|
||||
* delivered by a sibling instance (e.g. orbit-side `frank@nova.ddns.net`
|
||||
* viewed from a session logged in to nova) would otherwise show the globe.
|
||||
*
|
||||
* Compose with {@link useCanonicalUserView} at render sites: resolve the
|
||||
|
||||
@@ -66,9 +66,9 @@ beforeEach(() => {
|
||||
describe('getCanonicalUserView', () => {
|
||||
it('returns the input unchanged on cache miss', () => {
|
||||
const stub = makeUser({
|
||||
id: 'orbit-axel-stub',
|
||||
username: 'axel@nova.ddns.net',
|
||||
homeUserId: 'nova-axel-id',
|
||||
id: 'orbit-frank-stub',
|
||||
username: 'frank@nova.ddns.net',
|
||||
homeUserId: 'nova-frank-id',
|
||||
homeInstance: 'nova.ddns.net',
|
||||
avatarColor: 'lavender',
|
||||
});
|
||||
@@ -77,16 +77,16 @@ describe('getCanonicalUserView', () => {
|
||||
|
||||
it('returns the cached entry when one exists for the same canonical key', () => {
|
||||
const stub = makeUser({
|
||||
id: 'orbit-axel-stub',
|
||||
username: 'axel@nova.ddns.net',
|
||||
homeUserId: 'nova-axel-id',
|
||||
id: 'orbit-frank-stub',
|
||||
username: 'frank@nova.ddns.net',
|
||||
homeUserId: 'nova-frank-id',
|
||||
homeInstance: 'nova.ddns.net',
|
||||
avatarColor: 'lavender',
|
||||
});
|
||||
const homeFromNova = makeUser({
|
||||
id: 'nova-local-id',
|
||||
username: 'axel@nova.ddns.net',
|
||||
homeUserId: 'nova-axel-id',
|
||||
username: 'frank@nova.ddns.net',
|
||||
homeUserId: 'nova-frank-id',
|
||||
homeInstance: 'nova.ddns.net',
|
||||
avatarColor: 'teal',
|
||||
});
|
||||
@@ -106,9 +106,9 @@ describe('getCanonicalUserView', () => {
|
||||
useSpaceStore.getState().upsertUserView(someOther, '');
|
||||
|
||||
const stub = makeUser({
|
||||
id: 'orbit-axel-stub',
|
||||
username: 'axel@nova.ddns.net',
|
||||
homeUserId: 'nova-axel-id',
|
||||
id: 'orbit-frank-stub',
|
||||
username: 'frank@nova.ddns.net',
|
||||
homeUserId: 'nova-frank-id',
|
||||
homeInstance: 'nova.ddns.net',
|
||||
});
|
||||
expect(getCanonicalUserView(stub)).toBe(stub);
|
||||
|
||||
@@ -24,7 +24,7 @@ export function getCanonicalUserView(user: User): User {
|
||||
/**
|
||||
* Reactive lookup into the userViews cache. Subscribes to the specific cache
|
||||
* entry so the calling component re-renders when an upsert lands a better
|
||||
* view (e.g. nova's home view of Axel arriving after orbit's stub
|
||||
* view (e.g. nova's home view of Frank arriving after orbit's stub
|
||||
* populated the cache first). Returns the input unchanged on cache miss; the
|
||||
* site falls back to the current best information until the cache fills.
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user