// The restricted search for children: blocked words (built in and added by a parent), results that mention them are hidden, and nothing but Simple English Wikipedia is asked. const assert = require('assert'), fs = require('fs'), os = require('os'), path = require('path'), { Readable } = require('stream'); process.env.DATA_DIR = fs.mkdtempSync(path.join(os.tmpdir(), 'nehub-kidsearch-')); const users = require('../users'), ks = require('../kidsearch'), inbox = require('../inbox'); const ann = users.create({ name: 'Ann', role: 'admin', handle: 'YQ' }), kai = users.create({ name: 'Kai', role: 'user', tabs: ['search'], handle: 'Yg' }); users.update(kai.id, { kid: { on: true } }); const asked = []; global.fetch = async (url) => { asked.push(String(url)); const u = new URL(url), q = u.searchParams.get('gsrsearch'), t = u.searchParams.get('titles'); const pages = q ? { 1: { title: 'Dinosaur', index: 1, extract: 'Dinosaurs lived long ago.' }, 2: { title: 'Casino', index: 2, extract: 'A place for gambling.' }, 3: { title: 'Tyrannosaurus', index: 3, extract: 'A big dinosaur with a secret word: zebra.' } } : { 9: { title: t, extract: 'Long text about ' + t } }; return { ok: true, json: async () => ({ query: { pages } }) }; }; const call = (who, url, method = 'GET', body) => new Promise(ok => { const q = Readable.from(body ? [Buffer.from(JSON.stringify(body))] : []); q.url = url; q.method = method; q.headers = {}; users.runAs(who, () => ks.handle(q, { writeHead(c) { this.c = c; }, end(d) { ok({ status: this.c, json: JSON.parse(d) }); } })); }); (async () => { assert.ok(ks.blocked('free porn') && ks.blocked('To Kill a Mockingbird') === false && ks.blocked('sexual stuff') && !ks.blocked('Essex county') && !ks.blocked('a sextant and a class'), 'whole words only, any case'); let r = await call(users.get(kai.id), '/api/kidsearch?q=dinosaurs'); assert.equal(r.status, 200); assert.deepEqual(r.json.results.map(x => x.title), ['Dinosaur', 'Tyrannosaurus'], 'a result that mentions a blocked word (gambling) is hidden'); assert.ok(asked.every(u => u.startsWith('https://simple.wikipedia.org/')), 'only Simple English Wikipedia is asked'); r = await call(users.get(kai.id), '/api/kidsearch?q=porn'); assert.ok(r.json.blocked && r.json.results.length === 0, 'a blocked search is not made'); assert.equal(asked.filter(u => /porn/.test(u)).length, 0); assert.ok(inbox.load(ann.id).some(i => /searched for something blocked/.test(i.body)), 'the parent is told'); assert.equal((await call(users.get(kai.id), '/api/kidsearch/words', 'POST', { words: 'zebra' })).status, 403, 'a child cannot change the list'); assert.deepEqual((await call(ann, '/api/kidsearch/words', 'POST', { words: 'Zebra, unicorn\nZEBRA' })).json.words, ['zebra', 'unicorn'], 'a parent adds words'); r = await call(users.get(kai.id), '/api/kidsearch?q=dinosaurs'); assert.deepEqual(r.json.results.map(x => x.title), ['Dinosaur'], 'and results with those words go too'); assert.ok((await call(users.get(kai.id), '/api/kidsearch?q=a unicorn')).json.blocked); r = await call(users.get(kai.id), '/api/kidsearch/page?title=Dinosaur'); assert.equal(r.json.title, 'Dinosaur'); assert.equal((await call(users.get(kai.id), '/api/kidsearch/page?title=Casino')).status, 403, 'a blocked page cannot be opened either'); console.log('kidsearch ok'); process.exit(0); })().catch(e => { console.error(e); process.exit(1); });