diff --git a/README.md b/README.md index 434b626..9eefbff 100644 --- a/README.md +++ b/README.md @@ -85,8 +85,8 @@ They are JSON files placed in the `/targets` directory. - `from` *optional* | The "from" field of an email. This is used as fallback if no "from" is provided in the request. - `key` *optional* | A string used as API key if you want to restrict access to this target. - `redirect` *optional*: - - `success` *optional*: A valid URL to redirect the user if the mail was sent successful. - - `error` *optional*: A valid URL to redirect the user if the mail can't be sent due to an error. + - `success` *optional*: A valid relative or absolute URL to redirect the user if the mail was sent successful. + - `error` *optional*: A valid relative or absolute URL to redirect the user if the mail can't be sent due to an error. - `rateLimit` *required*: - `timespan` *required* | Timespan (in seconds) for the rate limiter to reset. - `requests` *required* | Allowed amount of requests in the given timespan. diff --git a/src/models/target.ts b/src/models/target.ts index d3a74e4..23f2c0f 100644 --- a/src/models/target.ts +++ b/src/models/target.ts @@ -25,19 +25,11 @@ export const targetModel = { }, "redirect.success": { type: "string", - presence: false, - url: { - schemes: ["http", "https"], - allowLocal: true - } + presence: false }, "redirect.error": { type: "string", - presence: false, - url: { - schemes: ["http", "https"], - allowLocal: true - } + presence: false }, key: { type: "string", diff --git a/src/router.ts b/src/router.ts index 6ab00cf..e77f42b 100644 --- a/src/router.ts +++ b/src/router.ts @@ -33,7 +33,7 @@ router.use("/:target", async (req: Request, res: Response, next: NextFunction) = // Check origin if(target.origin && target.origin !== req.header("origin")) { - if(target.redirect?.error) return res.redirect(target.redirect.error); + if(target.redirect?.error) return res.redirect(getRedirectUrl(req, target.redirect.error)); return res.status(403).end(); } @@ -42,7 +42,7 @@ router.use("/:target", async (req: Request, res: Response, next: NextFunction) = let bearer = /Bearer (.+)/.exec(req.headers.authorization); if(!bearer || bearer[1] !== target.key) { - if(target.redirect?.error) return res.redirect(target.redirect.error); + if(target.redirect?.error) return res.redirect(getRedirectUrl(req, target.redirect.error)); return res.status(401).end(); } } @@ -64,7 +64,7 @@ router.post("/:target", async (req: Request, res: Response) => { const form = formidable({}); form.parse(req, async (err, fields, files) => { if (err) { - if(target.redirect?.error) return res.redirect(target.redirect.error); + if(target.redirect?.error) return res.redirect(getRedirectUrl(req, target.redirect.error)); return res.status(500).send({ message: "Parse Error" }).end(); } else { const validationResult = validate(fields, postBody); @@ -81,7 +81,7 @@ router.post("/:target", async (req: Request, res: Response) => { let verified = await CaptchaService.verifyCaptcha(target.captcha, userCaptchaResponse); if(!verified) { - if(target.redirect?.error) return res.redirect(target.redirect.error); + if(target.redirect?.error) return res.redirect(getRedirectUrl(req, target.redirect.error)); return res.status(400).send({ message: "captcha verification failed" }).end(); } } @@ -98,12 +98,12 @@ router.post("/:target", async (req: Request, res: Response) => { let sent = await EmailService.sendMail(req.params.target, from, fieldSubject, fieldBody, files); if(sent instanceof Error || !sent) { - if(target.redirect?.error) return res.redirect(target.redirect.error); + if(target.redirect?.error) return res.redirect(getRedirectUrl(req, target.redirect.error)); return res.status(500).send({ message: (sent).message }).end(); } if(target.redirect?.success) { - return res.redirect(target.redirect.success); + return res.redirect(getRedirectUrl(req, target.redirect.success)); } return res.status(200).end(); @@ -111,6 +111,17 @@ router.post("/:target", async (req: Request, res: Response) => { }); }); +function getRedirectUrl(req: Request, targetRedirectUrl: string) { + let redirectUrl = targetRedirectUrl + + const urlPattern = /^(https?):\/\//; + if(!urlPattern.test(redirectUrl)) { + redirectUrl = (req.header('Referer') || '/') + redirectUrl; + } + + return redirectUrl +} + router.all("*", (req: Request, res: Response) => res.status(404).end()); export default router; \ No newline at end of file