diff --git a/feedback.js b/feedback.js index 47f5845..56a2055 100644 --- a/feedback.js +++ b/feedback.js @@ -6,6 +6,7 @@ const { rankLocalChunks, supportQueries, } = require('./retrieval'); +const { redactPublic } = require('./helpcenter'); const SITEMAP = 'https://feedback.omi.me/sitemap.xml'; const CACHE_MS = 60 * 60 * 1000; @@ -125,12 +126,6 @@ function feedbackPostFromHtml(html) { return result; } -function redactPublic(text) { - return String(text || '') - .replace(/\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}\b/gi, '[email]') - .replace(/(? String(process.env.HELP_FORUM_CHANNEL_ID || '').trim(); const { cleanDocument } = require('./retrieval'); +const { redactSensitive } = require('./privacy'); function articleUrls(xml) { return [...String(xml || '').matchAll(/(https:\/\/help\.omi\.me\/en\/articles\/[^<]+)<\/loc>/g)].map( @@ -14,9 +15,10 @@ function htmlToText(html) { return cleanDocument(chunk); } +// A stored copy of a Discord thread or a Feedback post is shown to the model and can be quoted to +// another customer. It passes the public issue boundary first, then loses any long digit run left. function redactPublic(text) { - return String(text || '') - .replace(/\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}\b/gi, '[email]') + return redactSensitive(text, { issue: true }) .replace(/(? { + const page = feedbackPage('https://feedback.omi.me/p/sync-fails', { + title: 'Sync fails for order #22777', + content: 'Sync fails with my key sk-abcdefgh12345678.\nI am at 12 Baker Street, London', + }); + for (const value of ['abcdefgh', '22777', 'Baker Street']) { + assert.equal(`${page.title}\n${page.body}`.includes(value), false, value); + } + assert.match(page.body, /Sync fails with my key \[token\]/); +}); diff --git a/test/helpcenter.test.js b/test/helpcenter.test.js index d3791cf..429156a 100644 --- a/test/helpcenter.test.js +++ b/test/helpcenter.test.js @@ -14,3 +14,21 @@ test('the help center sitemap yields article urls and the page text keeps the re assert.equal(/menu junk/.test(text), false); assert.equal(redactPublic('mail me at taj@example.com'), 'mail me at [email]'); }); + +test('a stored Discord help message passes the same redaction as a public issue', () => { + const out = redactPublic([ + 'My API key is sk-abcdefgh12345678 and the header was Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0.abc', + 'Order #22777 never arrived.', + 'Ship it to 12 Baker Street, London', + 'Ask @DorkKnight or <@123456789012345678>, or mail ada@example.com', + 'The app shows error 1011 on build 1.0.552.', + ].join('\n')); + for (const value of ['abcdefgh', 'eyJhbGci', '22777', 'Baker Street', 'DorkKnight', '123456789012345678', 'ada@example.com']) { + assert.equal(out.includes(value), false, value); + } + assert.match(out, /\[token\]/); + assert.match(out, /\[order number\]/); + assert.match(out, /\[address\]/); + assert.match(out, /\[Discord user\]/); + assert.match(out, /The app shows error 1011 on build 1\.0\.552\./); +});