@teleporthq/teleport-plugin-next-workflows 0.45.8 → 0.45.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -439,8 +439,8 @@ function canSendNewsletterEmail() {
439
439
 
440
440
  // A link to one of the site's pages carries the token in its fragment: a
441
441
  // fragment never reaches a server, a CDN log or a Referer (the page's first
442
- // head script keeps it). The site's own unsubscribe route reads it on the
443
- // server, so a link to it carries it in the query.
442
+ // head script keeps it). The site's own confirm and unsubscribe routes read it
443
+ // on the server, so a link to one of them carries it in the query.
444
444
  function pageLink(path, token) {
445
445
  return path + (path.indexOf('/api/') === 0 ? '?t=' : '#t=') + encodeURIComponent(token);
446
446
  }
@@ -1 +1 @@
1
- {"version":3,"file":"routes-code.d.ts","sourceRoot":"","sources":["../../../src/newsletter/routes-code.ts"],"names":[],"mappings":"AA0BA,6DAA6D;AAC7D,eAAO,MAAM,6BAA6B,KAAK,CAAA;AAoB/C,eAAO,MAAM,gCAAgC,QAAO,MAuCnD,CAAA;AAED,eAAO,MAAM,8BAA8B,QAAO,MAqBjD,CAAA;AAED,eAAO,MAAM,kCAAkC,QAAO,MA0ErD,CAAA"}
1
+ {"version":3,"file":"routes-code.d.ts","sourceRoot":"","sources":["../../../src/newsletter/routes-code.ts"],"names":[],"mappings":"AA4BA,6DAA6D;AAC7D,eAAO,MAAM,6BAA6B,KAAK,CAAA;AAoB/C,eAAO,MAAM,gCAAgC,QAAO,MAuCnD,CAAA;AA8BD,eAAO,MAAM,8BAA8B,QAAO,MAmDjD,CAAA;AAED,eAAO,MAAM,kCAAkC,QAAO,MAkDrD,CAAA"}
@@ -8,13 +8,14 @@
8
8
  * `footer`, `popup`, `form`), else `block`; errors are logged by code and
9
9
  * message only (never a database row); every answer is `{ ok: true, pending }`, after at least
10
10
  * `NEWSLETTER_MIN_RESPONSE_MS`, whatever happened to the address.
11
- * - `confirm` — POST `{ token }` → `{ ok, email? }`.
12
- * - `unsubscribe` — POST `{ token }` → `{ ok, email? }`; a GET with `?t=`
13
- * (a click in a mail client) answers a small page whose button POSTs it, so a
14
- * link scanner that opens every link unsubscribes nobody.
11
+ * - `confirm` and `unsubscribe` — POST `{ token }` → `{ ok, email? }`; a GET
12
+ * with `?t=` (a click in a mail client) answers a small page whose button
13
+ * POSTs it, so a link scanner that opens every link confirms and
14
+ * unsubscribes nobody.
15
15
  */
16
16
  import { securityRuntimeSpecifier } from '../security-runtime/security-runtime-code';
17
- import { NEWSLETTER_UNSUBSCRIBE_URL, NEWSLETTER_VISITOR_LIMIT, NEWSLETTER_VISITOR_SCOPE, newsletterHelperSpecifier, } from './newsletter-scope';
17
+ import { newsletterTokenSpec } from './helper-code';
18
+ import { NEWSLETTER_CONFIRM_URL, NEWSLETTER_UNSUBSCRIBE_URL, NEWSLETTER_VISITOR_LIMIT, NEWSLETTER_VISITOR_SCOPE, newsletterHelperSpecifier, } from './newsletter-scope';
18
19
  /** From `pages/api/newsletter/` to the project root. */
19
20
  const RELATIVE_PREFIX = '../../..';
20
21
  /** Confirm and unsubscribe attempts per visitor per hour. */
@@ -75,31 +76,7 @@ ${methodGuard(['POST'])}
75
76
  return res.status(200).json(answer);
76
77
  };
77
78
  `;
78
- export const generateNewsletterConfirmRoute = () => `${ROUTE_PREAMBLE}
79
-
80
- module.exports = async function handler(req, res) {
81
- ${methodGuard(['POST'])}
82
- if (!(await __security.rateLimitRequest(req, res, { scope: 'newsletter-confirm', limit: ${NEWSLETTER_LINK_VISITOR_LIMIT}, windowSeconds: 3600 }))) {
83
- return;
84
- }
85
- var body = readBody(req);
86
- var token = typeof body.token === 'string' ? body.token : '';
87
- if (!token) {
88
- return res.status(200).json({ ok: false });
89
- }
90
- try {
91
- var result = await __newsletter.withNewsletterDb(function (db) {
92
- return __newsletter.confirmNewsletter({ db: db, token: token, req: req });
93
- });
94
- return res.status(200).json(result.ok ? { ok: true, email: result.email } : { ok: false });
95
- } catch (err) {
96
- return __security.sendClientError(res, 503, 'We could not confirm the subscription. Please try again in a moment.', __newsletter.safeError(err));
97
- }
98
- };
99
- `;
100
- export const generateNewsletterUnsubscribeRoute = () => `${ROUTE_PREAMBLE}
101
-
102
- function escapeHtml(value) {
79
+ const LINK_PAGE_CODE = `function escapeHtml(value) {
103
80
  return String(value == null ? '' : value)
104
81
  .replace(/&/g, '&')
105
82
  .replace(/</g, '&lt;')
@@ -123,7 +100,63 @@ function sendPage(res, status, title, message, form) {
123
100
  'button{font:inherit;padding:10px 18px;border:0;border-radius:6px;background:#111;color:#fff;cursor:pointer}</style>' +
124
101
  '</head><body><h1>' + escapeHtml(title) + '</h1><p>' + escapeHtml(message) + '</p>' + (form || '') + '</body></html>'
125
102
  );
126
- }
103
+ }`;
104
+ const CONFIRM_LINK_DAYS = newsletterTokenSpec.confirmMaxAgeSeconds / 86400;
105
+ export const generateNewsletterConfirmRoute = () => `${ROUTE_PREAMBLE}
106
+
107
+ ${LINK_PAGE_CODE}
108
+
109
+ var NOT_A_LINK = 'This confirmation link does not work. A link works for ${CONFIRM_LINK_DAYS} days: sign up again to get a new one.';
110
+
111
+ module.exports = async function handler(req, res) {
112
+ ${methodGuard(['GET', 'POST'])}
113
+ if (!(await __security.rateLimitRequest(req, res, { scope: 'newsletter-confirm', limit: ${NEWSLETTER_LINK_VISITOR_LIMIT}, windowSeconds: 3600 }))) {
114
+ return;
115
+ }
116
+ if (req.method === 'GET') {
117
+ // Opening the link changes nothing (a mail client's link scanner opens it
118
+ // too, and double opt-in means the person's own action): the button does.
119
+ var linkToken = req.query && typeof req.query.t === 'string' ? req.query.t : '';
120
+ if (!__newsletter.verifyNewsletterToken(linkToken, 'confirm')) {
121
+ return sendPage(res, 200, 'Link not valid', NOT_A_LINK, '');
122
+ }
123
+ return sendPage(
124
+ res,
125
+ 200,
126
+ 'Confirm your subscription',
127
+ 'Receive the newsletter at this address?',
128
+ '<form method="post" action="${NEWSLETTER_CONFIRM_URL}"><input type="hidden" name="t" value="' +
129
+ escapeHtml(linkToken) + '"><button type="submit">Confirm subscription</button></form>'
130
+ );
131
+ }
132
+ var body = readBody(req);
133
+ var fromForm = String((req.headers && req.headers['content-type']) || '').indexOf('application/x-www-form-urlencoded') !== -1;
134
+ var token = typeof body.token === 'string' ? body.token : typeof body.t === 'string' ? body.t : '';
135
+ var result = { ok: false };
136
+ try {
137
+ if (token) {
138
+ result = await __newsletter.withNewsletterDb(function (db) {
139
+ return __newsletter.confirmNewsletter({ db: db, token: token, req: req });
140
+ });
141
+ }
142
+ } catch (err) {
143
+ if (fromForm) {
144
+ console.error('[newsletter] confirm failed:', __newsletter.safeError(err));
145
+ return sendPage(res, 503, 'Please try again', 'We could not confirm your subscription just now. Please try again in a moment.', '');
146
+ }
147
+ return __security.sendClientError(res, 503, 'We could not confirm the subscription. Please try again in a moment.', __newsletter.safeError(err));
148
+ }
149
+ if (fromForm) {
150
+ return result.ok
151
+ ? sendPage(res, 200, "You're subscribed", 'Thank you for confirming. You will receive the newsletter at this address.', '')
152
+ : sendPage(res, 200, 'Link not valid', NOT_A_LINK, '');
153
+ }
154
+ return res.status(200).json(result.ok ? { ok: true, email: result.email } : { ok: false });
155
+ };
156
+ `;
157
+ export const generateNewsletterUnsubscribeRoute = () => `${ROUTE_PREAMBLE}
158
+
159
+ ${LINK_PAGE_CODE}
127
160
 
128
161
  var NOT_A_LINK = 'This unsubscribe link does not work. Use the link in a newer email from us.';
129
162
 
@@ -1 +1 @@
1
- {"version":3,"file":"routes-code.js","sourceRoot":"","sources":["../../../src/newsletter/routes-code.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,EAAE,wBAAwB,EAAE,MAAM,2CAA2C,CAAA;AACpF,OAAO,EACL,0BAA0B,EAC1B,wBAAwB,EACxB,wBAAwB,EACxB,yBAAyB,GAC1B,MAAM,oBAAoB,CAAA;AAE3B,wDAAwD;AACxD,MAAM,eAAe,GAAG,UAAU,CAAA;AAElC,6DAA6D;AAC7D,MAAM,CAAC,MAAM,6BAA6B,GAAG,EAAE,CAAA;AAE/C,MAAM,cAAc,GAAG,6BAA6B,wBAAwB,CAAC,eAAe,CAAC;8BAC/D,yBAAyB,CAAC,eAAe,CAAC;;;;;;;;EAQtE,CAAA;AAEF,MAAM,WAAW,GAAG,CAAC,OAAiB,EAAU,EAAE,CAAC,SAAS,OAAO;KAChE,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,mBAAmB,MAAM,GAAG,CAAC;KAC7C,IAAI,CAAC,MAAM,CAAC;8BACe,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC;;IAE5C,CAAA;AAEJ,MAAM,CAAC,MAAM,gCAAgC,GAAG,GAAW,EAAE,CAAC,GAAG,cAAc;;;EAG7E,WAAW,CAAC,CAAC,MAAM,CAAC,CAAC;OAChB,wBAAwB;mDACoB,wBAAwB;8EACG,wBAAwB,aAAa,wBAAwB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAiC1I,CAAA;AAED,MAAM,CAAC,MAAM,8BAA8B,GAAG,GAAW,EAAE,CAAC,GAAG,cAAc;;;EAG3E,WAAW,CAAC,CAAC,MAAM,CAAC,CAAC;4FACqE,6BAA6B;;;;;;;;;;;;;;;;;CAiBxH,CAAA;AAED,MAAM,CAAC,MAAM,kCAAkC,GAAG,GAAW,EAAE,CAAC,GAAG,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA+B/E,WAAW,CAAC,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;gGACkE,6BAA6B;;;;;;;;;;;;;;qCAcxF,0BAA0B;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4B9D,CAAA"}
1
+ {"version":3,"file":"routes-code.js","sourceRoot":"","sources":["../../../src/newsletter/routes-code.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,EAAE,wBAAwB,EAAE,MAAM,2CAA2C,CAAA;AACpF,OAAO,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAA;AACnD,OAAO,EACL,sBAAsB,EACtB,0BAA0B,EAC1B,wBAAwB,EACxB,wBAAwB,EACxB,yBAAyB,GAC1B,MAAM,oBAAoB,CAAA;AAE3B,wDAAwD;AACxD,MAAM,eAAe,GAAG,UAAU,CAAA;AAElC,6DAA6D;AAC7D,MAAM,CAAC,MAAM,6BAA6B,GAAG,EAAE,CAAA;AAE/C,MAAM,cAAc,GAAG,6BAA6B,wBAAwB,CAAC,eAAe,CAAC;8BAC/D,yBAAyB,CAAC,eAAe,CAAC;;;;;;;;EAQtE,CAAA;AAEF,MAAM,WAAW,GAAG,CAAC,OAAiB,EAAU,EAAE,CAAC,SAAS,OAAO;KAChE,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,mBAAmB,MAAM,GAAG,CAAC;KAC7C,IAAI,CAAC,MAAM,CAAC;8BACe,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC;;IAE5C,CAAA;AAEJ,MAAM,CAAC,MAAM,gCAAgC,GAAG,GAAW,EAAE,CAAC,GAAG,cAAc;;;EAG7E,WAAW,CAAC,CAAC,MAAM,CAAC,CAAC;OAChB,wBAAwB;mDACoB,wBAAwB;8EACG,wBAAwB,aAAa,wBAAwB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAiC1I,CAAA;AAED,MAAM,cAAc,GAAG;;;;;;;;;;;;;;;;;;;;;;;;EAwBrB,CAAA;AAEF,MAAM,iBAAiB,GAAG,mBAAmB,CAAC,oBAAoB,GAAG,KAAK,CAAA;AAE1E,MAAM,CAAC,MAAM,8BAA8B,GAAG,GAAW,EAAE,CAAC,GAAG,cAAc;;EAE3E,cAAc;;2EAE2D,iBAAiB;;;EAG1F,WAAW,CAAC,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;4FAC8D,6BAA6B;;;;;;;;;;;;;;;qCAepF,sBAAsB;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4B1D,CAAA;AAED,MAAM,CAAC,MAAM,kCAAkC,GAAG,GAAW,EAAE,CAAC,GAAG,cAAc;;EAE/E,cAAc;;;;;EAKd,WAAW,CAAC,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;gGACkE,6BAA6B;;;;;;;;;;;;;;qCAcxF,0BAA0B;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4B9D,CAAA"}