diff --git a/tools/kofi-worker/email.js b/tools/kofi-worker/email.js index be93b63f..a3fff4a8 100644 --- a/tools/kofi-worker/email.js +++ b/tools/kofi-worker/email.js @@ -25,9 +25,13 @@ export function codeLines(code) { return lines.map((line, index) => (index < lines.length - 1 ? `${line}-` : line)) } -/** Folio's own link for a code (RedeemActivity, since 0.6.5): on an Android phone with Folio it adds the code in one tap. */ +/** + * The link in the email: a page on the site that shows the code and, on Android, opens Folio's own redeem link + * (folio://redeem, handled by RedeemActivity since 0.6.5). The email cannot link to folio:// itself, because Gmail does + * nothing with a custom scheme. The code sits after the #, so a browser never sends it to a server. + */ export function redeemLink(code) { - return `folio://redeem?c=${encodeURIComponent(String(code))}` + return `https://foliolauncher.com/redeem/#${encodeURIComponent(String(code))}` } const SUBJECT = 'Your Folio supporter code' @@ -44,7 +48,7 @@ export function supporterEmail({ name = '', code, pool = '' }) { '', ` ${code}`, '', - 'On your Android phone, this link adds it in one tap:', + 'On your Android phone, this link opens a page that adds it to Folio:', ` ${redeemLink(code)}`, '', 'In Folio: Settings › Supporter › Redeem a Code, and paste it in. It is checked on your phone, so it works', @@ -109,10 +113,10 @@ export function supporterEmail({ name = '', code, pool = '' }) {
| - Open in Folio + Add to Folio |
On your Android phone, this adds the code in one tap.
+Opens a page that adds the code in Folio on your Android phone.
In Folio: Settings › Supporter › Redeem a Code, and paste it in. It is checked on your phone, so it works offline and tells nobody that you supported.
diff --git a/tools/kofi-worker/email.test.mjs b/tools/kofi-worker/email.test.mjs index f8a1ba10..b3d68d30 100644 --- a/tools/kofi-worker/email.test.mjs +++ b/tools/kofi-worker/email.test.mjs @@ -1,6 +1,6 @@ /** * The supporter email: McCal's words kept as written, the HTML safe to build from a name anyone can type on Ko-fi, and - * the "Open in Folio" link in the exact shape RedeemActivity (app/.../RedeemActivity.kt, since 0.6.5) accepts. + * the button's link to the redeem page on foliolauncher.com, which hands the code to Folio's RedeemActivity. * Run with `node --test email.test.mjs`; no network. */ import assert from 'node:assert/strict' @@ -53,14 +53,15 @@ test('the HTML has no script, no javascript: link, and reaches out to nowhere bu for (const line of codeLines(CODE)) assert.ok(html.includes(line)) }) -test('the Open in Folio link is the one RedeemActivity reads', () => { +test('the button opens the redeem page on the site, with the code after the # so it never reaches a server', () => { const link = redeemLink(CODE) - assert.equal(link, `folio://redeem?c=${CODE}`) - assert.ok(supporterEmail({ code: CODE, pool: 'm1' }).html.includes(`href="${link}"`)) - assert.ok(supporterEmail({ code: CODE, pool: 'm1' }).text.includes(link)) - // The app's redeemCode(): the prefix, a c= parameter, and 20 to 200 letters, digits and hyphens. - const query = link.slice('folio://redeem'.length).split('?')[1] - const code = decodeURIComponent(query.split('&').find((p) => p.startsWith('c=')).slice(2)) - assert.ok(code.length >= 20 && code.length <= 200 && /^[A-Za-z0-9-]+$/.test(code)) - assert.equal(code, CODE) + assert.equal(link, `https://foliolauncher.com/redeem/#${CODE}`) + const { html, text } = supporterEmail({ code: CODE, pool: 'm1' }) + assert.ok(html.includes(`href="${link}"`)) + assert.ok(text.includes(link)) + assert.ok(!html.includes('folio://') && !text.includes('folio://'), 'Gmail does nothing with a custom scheme') + // The page (folio-site public/redeem.js) takes letters, digits and hyphens, 20 to 200 of them, from the fragment. + const fragment = decodeURIComponent(link.split('#')[1]) + assert.ok(/^[A-Za-z0-9-]{20,200}$/.test(fragment)) + assert.equal(fragment, CODE) }) diff --git a/tools/kofi-worker/worker.test.mjs b/tools/kofi-worker/worker.test.mjs index 57fe13e8..2fe29034 100644 --- a/tools/kofi-worker/worker.test.mjs +++ b/tools/kofi-worker/worker.test.mjs @@ -198,6 +198,6 @@ test('the email goes to Resend as both HTML and plain text, with the link and th assert.equal(body.reply_to, 'me@example.com') assert.equal(body.subject, 'Your Folio supporter code') assert.ok(body.text.includes('CODE-1') && body.html.includes('CODE-1')) - assert.ok(body.html.includes('href="folio://redeem?c=CODE-1"')) + assert.ok(body.html.includes('href="https://foliolauncher.com/redeem/#CODE-1"')) assert.equal(DB.handled.get('m1').emailed, 1) })