openvibers/openvibe.directory Commits

Establish Directory session on signed-in arrival (#11)

OP OpenVibers committed 2 days ago · 933e350170 · 2 files, +24 −1

Changes

ddiff --git a/server/app.js b/server/app.js
iindex 2db6912..e884e18 100644
---- a/server/app.js
++++ b/server/app.js
@@@ -31,7 +31,13 @@ function createApp({store=createStore(),peopleStore=null,auth=createAuth()}={}){
app.get('/robots.txt',(_q,r)=>r.type('text').send('User-agent: *\nAllow: /\nSitemap: https://openvibe.directory/sitemap.xml\n'));
app.get('/llms.txt',(_q,r)=>r.type('text').send('# OpenVibe.Directory\n\nSource-linked listings with last checked dates.\n\n'+Object.entries(kinds).map(([id,name])=>`- [${name}](https://openvibe.directory/kinds/${id}): ${store.list(id).length} entries`).join('\n')+'\n\nJSON: https://openvibe.directory/api/v1/entries\n'));
app.get('/sitemap.xml',(_q,r)=>{const paths=['/',...Object.keys(kinds).map(k=>`/kinds/${k}`),...all().map(v.entryPath)];r.type('application/xml').send('<?xml version="1.0" encoding="UTF-8"?><urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">'+paths.map(p=>`<url><loc>https://openvibe.directory${v.esc(p)}</loc></url>`).join('')+'</urlset>');});
-- app.get('/',(q,r)=>r.send(v.page('Directories',v.home(kinds,counts(),all()),'/',[{'@context':'https://schema.org','@type':'WebSite',name:'OpenVibe.Directory',url:'https://openvibe.directory/',potentialAction:{'@type':'SearchAction',target:'https://openvibe.directory/search?q={search_term_string}','query-input':'required name=search_term_string'}}])));
++ app.get('/',auth?auth.optionalAuth():(_q,_r,next)=>next(),(q,r)=>{
++ r.set('Cache-Control','private, no-store');r.vary('Accept');r.vary('Cookie');
++ const browser=/\btext\/html\b/.test(q.get('accept')||'')&&!/bot|crawl|spider|slurp/i.test(q.get('user-agent')||'');
++ const guest=/(?:^|;\s*)ov_sso_hint=guest(?:;|$)/.test(q.get('cookie')||'');
++ if(auth&&!q.user&&browser&&!guest&&q.query.sso!=='none')return r.redirect(302,'/auth/login?silent=1');
++ return r.send(v.page('Directories',v.home(kinds,counts(),all()),'/',[{'@context':'https://schema.org','@type':'WebSite',name:'OpenVibe.Directory',url:'https://openvibe.directory/',potentialAction:{'@type':'SearchAction',target:'https://openvibe.directory/search?q={search_term_string}','query-input':'required name=search_term_string'}}]));
++ });
app.get('/search',(q,r)=>{const kind=String(q.query.kind||'');if(kind&&!kinds[kind])return r.sendStatus(404);const term=String(q.query.q||'').slice(0,120);const rows=search(term,kind).slice(0,200);r.send(v.page('Search directory',v.listing(kind||'all','Search directory',rows,term),`/search?q=${encodeURIComponent(term)}`));});
app.get('/kinds/:kind',(q,r)=>{const kind=q.params.kind;if(!kinds[kind])return r.sendStatus(404);r.send(v.page(kinds[kind],v.listing(kind,kinds[kind],store.list(kind)),q.path));});
app.get('/entries/:kind/:slug',(q,r)=>{const e=find(q.params.kind,q.params.slug);if(!e)return r.sendStatus(404);r.vary('Accept');if(q.accepts(['html','text/markdown'])==='text/markdown')return r.type('text/markdown').send(v.markdown(e));r.send(v.page(e.name,v.detail(e),q.path,[{'@context':'https://schema.org','@type':e.kind==='businesses'?'LocalBusiness':e.kind==='people'?'Person':'Thing',name:e.name,description:e.description,url:`https://openvibe.directory${q.path}`,dateModified:e.last_checked,sameAs:e.sources.map(s=>s.url)}]));});
ddiff --git a/test/directory.test.js b/test/directory.test.js
iindex d247f04..5e636eb 100644
---- a/test/directory.test.js
++++ b/test/directory.test.js
@@@ -48,3 +48,20 @@ test('directory and model searches use the shared composer and preserve the kind
assert.equal(result.status,200);assert.match(await result.text(),/name="q"[^>]*>Gemini<\/textarea>/);
}finally{server.close();}
});
++test('home silently checks Network only for an unrecognized browser visitor',async()=>{
++ const store=createStore({fetchImpl:async()=>({ok:false,status:503})});store.start=()=>{};
++ const auth={router:()=>((_q,_r,next)=>next()),optionalAuth:()=>((q,_r,next)=>{if((q.get('cookie')||'').includes('ov_token=known'))q.user={subject_id:'usr_12345678'};next();})};
++ const server=createApp({store,auth}).listen(0,'127.0.0.1');await new Promise(resolve=>server.once('listening',resolve));
++ const base=`http://127.0.0.1:${server.address().port}`;
++ const get=(path,headers)=>fetch(base+path,{headers,redirect:'manual'});
++ try{
++ let r=await get('/',{accept:'text/html'});assert.equal(r.status,302);assert.equal(r.headers.get('location'),'/auth/login?silent=1');assert.match(r.headers.get('cache-control'),/no-store/);
++ for(const [path,headers] of [
++ ['/',{accept:'text/html',cookie:'ov_sso_hint=guest'}],
++ ['/?sso=none',{accept:'text/html'}],
++ ['/',{accept:'text/html',cookie:'ov_token=known'}],
++ ['/',{accept:'text/html','user-agent':'A search crawler'}],
++ ['/',{accept:'application/json'}],
++ ]){r=await get(path,headers);assert.equal(r.status,200,JSON.stringify({path,headers}));}
++ }finally{server.close();}
++});