diff --git a/README.md b/README.md index bd7ed8b..1b463af 100644 --- a/README.md +++ b/README.md @@ -86,8 +86,8 @@ They are JSON files placed in the `/targets` directory. - `subjectPrefix` *optional* | A target-wide prefix for the email subject. - `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 2611eea..9efc16a 100644 --- a/src/models/target.ts +++ b/src/models/target.ts @@ -29,19 +29,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 d46b674..51cab2f 100644 --- a/src/router.ts +++ b/src/router.ts @@ -7,6 +7,7 @@ import validate from "./services/validate"; import {postBody} from "./models/post"; import {EmailService} from "./services/email"; import {CaptchaService} from "./services/captcha"; +import getRedirectUrl from "./util/redirect"; const router: Router = Router(); @@ -33,7 +34,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 +43,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 +65,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 +82,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(); } } @@ -99,12 +100,12 @@ router.post("/:target", async (req: Request, res: Response) => { let sent = await EmailService.sendMail(req.params.target, from, subject, 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(); diff --git a/src/util/redirect.ts b/src/util/redirect.ts new file mode 100755 index 0000000..29cb2f4 --- /dev/null +++ b/src/util/redirect.ts @@ -0,0 +1,20 @@ +import {Request} from "express"; + +/** + * Create absolute Url from relative redirectUrl + * @param req incoming Request + * @param targetRedirectUrl redirectUrl from target + * @returns String + */ +function getRedirectUrl(req: Request, targetRedirectUrl: string) { + let redirectUrl = targetRedirectUrl + + const urlPattern = /^(https?):\/\//; + if(!urlPattern.test(redirectUrl)) { + redirectUrl = (req.header('Referer') || '/') + redirectUrl; + } + + return redirectUrl +} + +export default getRedirectUrl; \ No newline at end of file