Don't crash if email address has sub-address with special characters

Emails with [sub-addressing](https://en.wikipedia.org/wiki/Email_address#Sub-addressing) should not
cause the donations flow to crash. It currently does because the vipps redirect URL validation fails
because of the special characters involved, namely "+", e.g. "olav+subscriptions@example.com".
This commit is contained in:
olaven 2025-06-18 22:47:59 +02:00
parent 0e77c35fb2
commit 6a62923d6d
2 changed files with 12 additions and 5 deletions

View File

@ -3,6 +3,7 @@ import "jsr:@std/dotenv/load";
import { encodeHex } from "jsr:@std/encoding/hex"; import { encodeHex } from "jsr:@std/encoding/hex";
import { getHostUrl } from "../utils.ts"; import { getHostUrl } from "../utils.ts";
import { STATUS_CODE } from "$fresh/server.ts"; import { STATUS_CODE } from "$fresh/server.ts";
import { base } from "npm:@faker-js/faker";
const config = { const config = {
clientId: Deno.env.get("VIPPS_CLIENT_ID"), clientId: Deno.env.get("VIPPS_CLIENT_ID"),
@ -50,6 +51,12 @@ const getAccessToken = async function () {
export const createAgreement = async function (email: string) { export const createAgreement = async function (email: string) {
const token = await getAccessToken(); const token = await getAccessToken();
const amount = 5000; // 50 NOK const amount = 5000; // 50 NOK
// in case of special characters, like sub-addresses added
// with +, e.g. "name+subscriptions@domain.com"
const urlEncodedEmail = encodeURIComponent(email);
const redirectUrl = `${getHostUrl()}/donations-success?urlEncodedEmail=${urlEncodedEmail}`;
console.log(redirectUrl, "HER ER DET");
const response = await fetch(`${config.baseUrl}/recurring/v3/agreements/`, { const response = await fetch(`${config.baseUrl}/recurring/v3/agreements/`, {
method: "POST", method: "POST",
// @ts-ignore // @ts-ignore
@ -74,7 +81,7 @@ export const createAgreement = async function (email: string) {
currency: "NOK", currency: "NOK",
}, },
// email is used to identify the user in the success page // email is used to identify the user in the success page
merchantRedirectUrl: `${getHostUrl()}/donations-success?email=${email}`, merchantRedirectUrl: redirectUrl,
merchantAgreementUrl: `${getHostUrl()}`, merchantAgreementUrl: `${getHostUrl()}`,
productName: "Månedlig støtte til NRSS", productName: "Månedlig støtte til NRSS",
}), }),

View File

@ -5,7 +5,9 @@ import { validateEmail } from "../lib/utils.ts";
export const handler: Handlers = { export const handler: Handlers = {
async GET(request, ctx) { async GET(request, ctx) {
const url = new URL(request.url); const url = new URL(request.url);
const email = url.searchParams.get("email"); const urlEncodedEmail = url.searchParams.get("urlEncodedEmail");
const email = urlEncodedEmail ? decodeURIComponent(urlEncodedEmail) : null;
if (!email) { if (!email) {
console.error("Missing email in query params", request.url); console.error("Missing email in query params", request.url);
return Response.redirect("/donations-error"); return Response.redirect("/donations-error");
@ -34,9 +36,7 @@ export const handler: Handlers = {
export default function () { export default function () {
return ( return (
<div className="my-16 text-center flex flex-col items-center min-h-screen "> <div className="my-16 text-center flex flex-col items-center min-h-screen ">
<h1 className="text-6xl mb-8"> <h1 className="text-6xl mb-8">🙏🌟😊💖</h1>
🙏🌟😊💖
</h1>
<p className="text-4xl mb-4"> <p className="text-4xl mb-4">
Tusen takk! Jeg er veldig takknemlig for all støtte. Tusen takk! Jeg er veldig takknemlig for all støtte.
</p> </p>