char-slop/stars.hackery.site
git clone https://git.t4t.associates/char-slop/stars.hackery.site
92004f9
main
1import { assert , assertEquals } from "@std/assert" ; 2import { DatabaseSync } from "node:sqlite" ; 3import { Auth , type Session } from "./auth.ts" ; 4import { type Actor , Hydrant } from "./hydrant.ts" ; 5import { handler } from "./main.ts" ; 6import { Star } from "./records.ts" ; 7import { Index } from "./sync.ts" ; 8import { TitleLookup } from "./title.ts" ; 9 10Deno . test ( "public profile escapes comments and shows handle rather than display name" , async () => { 11const db = new DatabaseSync ( ":memory:" ); 12try { 13const auth = new Auth ( db , new URL ( "http://127.0.0.1:8000" )); 14const hydrant = new class extends Hydrant { 15override actor ( _identifier :string ) :Promise < Actor > { 16return Promise . resolve ({ 17did :"did:plc:abcdefgh" , 18handle :"char.lt" , 19pds :"https://pds.example.org/" , 20avatar :"https://pds.example.org/avatar" , 21}); 22} 23override stars ( _did :string , _cursor ?:string ) { 24return Promise . resolve ({ 25stars :[{ 26uri :"at://did:plc:abcdefgh/site.hackery.stars.star/3mgabcdefghij" , 27link :"https://example.com/" , 28star :Star . build ({ 29url :"https://example.com/" , 30title :"A useful project" , 31comment :"<script>alert(1)</script>" , 32createdAt :"2026-09-24T10:00:00Z" , 33}), 34}], 35cursor :undefined , 36}); 37} 38}( new URL ( "http://127.0.0.1:3000" )); 39const index = new Index ( db , hydrant ); 40const res = await handler ( new Request ( "http://127.0.0.1:8000/char.lt" ), { 41 auth, 42 hydrant, 43 index, 44titles :new TitleLookup ( db ), 45}); 46assertEquals ( res . status , 200 ); 47const body = await res . text (); 48assert ( body . includes ( "char.lt" )); 49assert ( body . includes ( ">A useful project</a>" )); 50assert ( body . includes ( ">example.com</small>" )); 51assert ( body . includes ( "Starred: 24 September 2026 at 10:00" )); 52assert ( body . includes ( "<script>alert(1)</script>" )); 53assert ( ! body . includes ( "<script>" )); 54assert ( ! body . includes ( "displayName" )); 55} finally { 56db . close (); 57} 58}); 59 60Deno . test ( "unverified handle is shown with a readable DID profile URL" , async () => { 61const db = new DatabaseSync ( ":memory:" ); 62try { 63const auth = new Auth ( db , new URL ( "http://127.0.0.1:8000" )); 64const hydrant = new class extends Hydrant { 65override actor ( _identifier :string ) :Promise < Actor > { 66return Promise . resolve ({ 67did :"did:plc:abcdefgh" , 68handle :"claimed.example.com" , 69handleVerified :false , 70pds :"https://pds.example.org/" , 71}); 72} 73override stars ( _did :string , _cursor ?:string ) { 74return Promise . resolve ({ stars :[], cursor :undefined }); 75} 76}( new URL ( "http://127.0.0.1:3000" )); 77auth . session = () => 78Promise . resolve ({ 79id :"test-session" , 80did :"did:plc:abcdefgh" , 81csrf :"test-csrf" , 82oauth :{}, 83} as unknown as Session ); 84const app = { 85 auth, 86 hydrant, 87index :new Index ( db , hydrant ), 88titles :new TitleLookup ( db ), 89}; 90const profile = await handler ( 91new Request ( "http://127.0.0.1:8000/did:plc:abcdefgh" ), 92app , 93); 94assertEquals ( profile . status , 200 ); 95const body = await profile . text (); 96assert ( body . includes ( "claimed.example.com" )); 97assert ( body . includes ( "(unverified)" )); 98assert ( 99body . includes ( 100'<nav><a href="/share">Add Star</a><a href="/did:plc:abcdefgh">claimed.example.com</a></nav>' , 101), 102); 103assert ( ! body . includes ( 'href="/login">Sign in</a>' )); 104const signIn = await handler ( 105new Request ( "http://127.0.0.1:8000/login" ), 106app , 107); 108assertEquals ( signIn . headers . get ( "location" ), "/" ); 109const browse = await handler ( 110new Request ( "http://127.0.0.1:8000/go?handle=did%3Aplc%3Aabcdefgh" ), 111app , 112); 113assertEquals ( browse . headers . get ( "location" ), "/did:plc:abcdefgh" ); 114} finally { 115db . close (); 116} 117});