Public-release prep: ELv2 license, README/CLA/NOTICE, SSRF safeFetch, identifier genericization, export tooling

This commit is contained in:
Jannis Braun
2026-06-22 16:04:03 +02:00
parent c0a6477059
commit 8dd76f3435
44 changed files with 1272 additions and 267 deletions
+5 -5
View File
@@ -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"', () => {
+1 -1
View File
@@ -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 {
+9 -9
View File
@@ -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);
});
});
+4 -4
View File
@@ -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
+11 -11
View File
@@ -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);
+1 -1
View File
@@ -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.
*