@payyo/ptp-js 2.1.0 → 2.2.0

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.
package/dist/index.d.ts CHANGED
@@ -23,6 +23,7 @@ export declare type FieldConfig = {
23
23
  endpoint: string;
24
24
  mode: Mode;
25
25
  debug: boolean;
26
+ parentOrigin: string;
26
27
  };
27
28
 
28
29
  export declare type FieldEvent = {
package/dist/index.es.js CHANGED
@@ -8,12 +8,36 @@ var FieldType = /* @__PURE__ */ ((FieldType2) => {
8
8
  FieldType2["SecurityCode"] = "securityCode";
9
9
  return FieldType2;
10
10
  })(FieldType || {});
11
+ function originAllowed(origin, allowed) {
12
+ if (!origin) {
13
+ return false;
14
+ }
15
+ return allowed.includes(origin);
16
+ }
17
+ function formIdMatches(incoming, expected) {
18
+ if (!incoming || !expected) {
19
+ return false;
20
+ }
21
+ return incoming === expected;
22
+ }
23
+ function fieldOriginFrom(fieldUrl) {
24
+ if (!fieldUrl) {
25
+ return "";
26
+ }
27
+ try {
28
+ return new URL(fieldUrl).origin;
29
+ } catch {
30
+ return "";
31
+ }
32
+ }
11
33
  function createForm(config) {
12
34
  const fields = {};
13
35
  const fieldNames = [];
14
36
  const callbacks = {};
15
37
  const formId = generateRandomId();
16
- let fieldUrl = config.fieldUrl && config.mode === Mode.Test ? config.fieldUrl : "https://cdn.ptp.payyo.ch/ptp-js/2.1.0/field.html";
38
+ let fieldUrl = config.fieldUrl && config.mode === Mode.Test ? config.fieldUrl : "https://cdn.ptp.payyo.ch/ptp-js/2.2.0/field.html";
39
+ const fieldOrigin = fieldOriginFrom(fieldUrl);
40
+ const sendTarget = fieldOrigin || "*";
17
41
  const EVENT_ON_CHANGE = "change";
18
42
  const EVENT_ON_READY = "ready";
19
43
  const EVENT_ON_FOCUS = "focus";
@@ -37,6 +61,7 @@ function createForm(config) {
37
61
  // @ts-ignore
38
62
  src: `${fieldUrl}?${new URLSearchParams({
39
63
  form_id: formId,
64
+ parent_origin: window.location.origin,
40
65
  field_name: field.name,
41
66
  field_type: field.type,
42
67
  field_names: fieldNames,
@@ -74,7 +99,7 @@ function createForm(config) {
74
99
  log("send message", message);
75
100
  if (mainFieldName) {
76
101
  const mainIFrameName = fields[mainFieldName].iFrameName;
77
- window.frames[mainIFrameName].postMessage(message, "*");
102
+ window.frames[mainIFrameName].postMessage(message, sendTarget);
78
103
  }
79
104
  });
80
105
  }
@@ -97,7 +122,7 @@ function createForm(config) {
97
122
  for (let [, field] of Object.entries(fields)) {
98
123
  const iframe = window.frames[field.iFrameName];
99
124
  if (iframe) {
100
- iframe.postMessage({ type: "checkFocus" }, "*");
125
+ iframe.postMessage({ type: "checkFocus", formId }, sendTarget);
101
126
  }
102
127
  }
103
128
  }
@@ -178,11 +203,12 @@ function createForm(config) {
178
203
  }
179
204
  window.frames[fields[fieldName].iFrameName].postMessage({
180
205
  type: "setStyle",
206
+ formId,
181
207
  params: {
182
208
  selector,
183
209
  rules: cssRules
184
210
  }
185
- }, "*");
211
+ }, sendTarget);
186
212
  },
187
213
  destroy: function() {
188
214
  var _a;
@@ -198,9 +224,16 @@ function createForm(config) {
198
224
  };
199
225
  function receiveMessage(message) {
200
226
  const event = message.data;
201
- if (formId !== event.formId) {
227
+ if (!formIdMatches(event.formId, formId)) {
202
228
  return;
203
229
  }
230
+ if (fieldOrigin && !originAllowed(message.origin, [fieldOrigin])) {
231
+ log("dropping message from disallowed origin", message.origin, event);
232
+ return;
233
+ }
234
+ if (!fieldOrigin) {
235
+ log("field origin unknown, skipping origin check on received message", event);
236
+ }
204
237
  log(`message received of type "${event.type}"`, event);
205
238
  const handlers2 = {
206
239
  fieldReady: (event2) => {
package/dist/index.js CHANGED
@@ -10,12 +10,36 @@ var FieldType = /* @__PURE__ */ ((FieldType2) => {
10
10
  FieldType2["SecurityCode"] = "securityCode";
11
11
  return FieldType2;
12
12
  })(FieldType || {});
13
+ function originAllowed(origin, allowed) {
14
+ if (!origin) {
15
+ return false;
16
+ }
17
+ return allowed.includes(origin);
18
+ }
19
+ function formIdMatches(incoming, expected) {
20
+ if (!incoming || !expected) {
21
+ return false;
22
+ }
23
+ return incoming === expected;
24
+ }
25
+ function fieldOriginFrom(fieldUrl) {
26
+ if (!fieldUrl) {
27
+ return "";
28
+ }
29
+ try {
30
+ return new URL(fieldUrl).origin;
31
+ } catch {
32
+ return "";
33
+ }
34
+ }
13
35
  function createForm(config) {
14
36
  const fields = {};
15
37
  const fieldNames = [];
16
38
  const callbacks = {};
17
39
  const formId = generateRandomId();
18
- let fieldUrl = config.fieldUrl && config.mode === Mode.Test ? config.fieldUrl : "https://cdn.ptp.payyo.ch/ptp-js/2.1.0/field.html";
40
+ let fieldUrl = config.fieldUrl && config.mode === Mode.Test ? config.fieldUrl : "https://cdn.ptp.payyo.ch/ptp-js/2.2.0/field.html";
41
+ const fieldOrigin = fieldOriginFrom(fieldUrl);
42
+ const sendTarget = fieldOrigin || "*";
19
43
  const EVENT_ON_CHANGE = "change";
20
44
  const EVENT_ON_READY = "ready";
21
45
  const EVENT_ON_FOCUS = "focus";
@@ -39,6 +63,7 @@ function createForm(config) {
39
63
  // @ts-ignore
40
64
  src: `${fieldUrl}?${new URLSearchParams({
41
65
  form_id: formId,
66
+ parent_origin: window.location.origin,
42
67
  field_name: field.name,
43
68
  field_type: field.type,
44
69
  field_names: fieldNames,
@@ -76,7 +101,7 @@ function createForm(config) {
76
101
  log("send message", message);
77
102
  if (mainFieldName) {
78
103
  const mainIFrameName = fields[mainFieldName].iFrameName;
79
- window.frames[mainIFrameName].postMessage(message, "*");
104
+ window.frames[mainIFrameName].postMessage(message, sendTarget);
80
105
  }
81
106
  });
82
107
  }
@@ -99,7 +124,7 @@ function createForm(config) {
99
124
  for (let [, field] of Object.entries(fields)) {
100
125
  const iframe = window.frames[field.iFrameName];
101
126
  if (iframe) {
102
- iframe.postMessage({ type: "checkFocus" }, "*");
127
+ iframe.postMessage({ type: "checkFocus", formId }, sendTarget);
103
128
  }
104
129
  }
105
130
  }
@@ -180,11 +205,12 @@ function createForm(config) {
180
205
  }
181
206
  window.frames[fields[fieldName].iFrameName].postMessage({
182
207
  type: "setStyle",
208
+ formId,
183
209
  params: {
184
210
  selector,
185
211
  rules: cssRules
186
212
  }
187
- }, "*");
213
+ }, sendTarget);
188
214
  },
189
215
  destroy: function() {
190
216
  var _a;
@@ -200,9 +226,16 @@ function createForm(config) {
200
226
  };
201
227
  function receiveMessage(message) {
202
228
  const event = message.data;
203
- if (formId !== event.formId) {
229
+ if (!formIdMatches(event.formId, formId)) {
204
230
  return;
205
231
  }
232
+ if (fieldOrigin && !originAllowed(message.origin, [fieldOrigin])) {
233
+ log("dropping message from disallowed origin", message.origin, event);
234
+ return;
235
+ }
236
+ if (!fieldOrigin) {
237
+ log("field origin unknown, skipping origin check on received message", event);
238
+ }
206
239
  log(`message received of type "${event.type}"`, event);
207
240
  const handlers2 = {
208
241
  fieldReady: (event2) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@payyo/ptp-js",
3
- "version": "2.1.0",
3
+ "version": "2.2.0",
4
4
  "description": "JS library for Payyo Tokenization service (PTP)",
5
5
  "private": false,
6
6
  "author": "developers@payyo.ch",
package/src/form/form.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import {Field, FieldEvent, Form, FormConfig, Message, MessageResponse, Mode, SetStyleEvent} from "../types.ts";
2
+ import {fieldOriginFrom, formIdMatches, originAllowed} from "../messaging.ts";
2
3
 
3
4
  export function createForm(config: FormConfig): Form {
4
5
  const fields: Record<string, Field> = {};
@@ -8,6 +9,9 @@ export function createForm(config: FormConfig): Form {
8
9
 
9
10
  let fieldUrl = (config.fieldUrl && config.mode === Mode.Test) ? config.fieldUrl : import.meta.env.VITE_PTP_FIELD_URL;
10
11
 
12
+ const fieldOrigin = fieldOriginFrom(fieldUrl);
13
+ const sendTarget = fieldOrigin || '*';
14
+
11
15
  const EVENT_ON_CHANGE = 'change';
12
16
  const EVENT_ON_READY = 'ready';
13
17
  const EVENT_ON_FOCUS = 'focus';
@@ -37,6 +41,7 @@ export function createForm(config: FormConfig): Form {
37
41
  // @ts-ignore
38
42
  src: `${fieldUrl}?${(new URLSearchParams({
39
43
  form_id: formId,
44
+ parent_origin: window.location.origin,
40
45
  field_name: field.name,
41
46
  field_type: field.type,
42
47
  field_names: fieldNames,
@@ -83,7 +88,7 @@ export function createForm(config: FormConfig): Form {
83
88
  if (mainFieldName) {
84
89
  const mainIFrameName = fields[mainFieldName].iFrameName;
85
90
  // @ts-ignore
86
- window.frames[mainIFrameName].postMessage(message, '*');
91
+ window.frames[mainIFrameName].postMessage(message, sendTarget);
87
92
  }
88
93
  });
89
94
  }
@@ -112,7 +117,7 @@ export function createForm(config: FormConfig): Form {
112
117
  // @ts-ignore
113
118
  const iframe = window.frames[field.iFrameName];
114
119
  if (iframe) {
115
- iframe.postMessage({type: 'checkFocus'}, '*');
120
+ iframe.postMessage({type: 'checkFocus', formId: formId}, sendTarget);
116
121
  }
117
122
  }
118
123
  }
@@ -204,11 +209,12 @@ export function createForm(config: FormConfig): Form {
204
209
  // @ts-ignore
205
210
  window.frames[fields[fieldName].iFrameName].postMessage({
206
211
  type: 'setStyle',
212
+ formId: formId,
207
213
  params: {
208
214
  selector: selector,
209
215
  rules: cssRules,
210
216
  } as SetStyleEvent
211
- }, '*');
217
+ }, sendTarget);
212
218
  },
213
219
  destroy: function () {
214
220
  window.removeEventListener('message', receiveMessage, false);
@@ -224,10 +230,18 @@ export function createForm(config: FormConfig): Form {
224
230
 
225
231
  function receiveMessage(message: MessageEvent<Message>) {
226
232
  const event: Message = message.data;
227
- if (formId !== event.formId) {
233
+ if (!formIdMatches(event.formId, formId)) {
228
234
  return;
229
235
  }
230
236
 
237
+ if (fieldOrigin && !originAllowed(message.origin, [fieldOrigin])) {
238
+ log('dropping message from disallowed origin', message.origin, event);
239
+ return;
240
+ }
241
+ if (!fieldOrigin) {
242
+ log('field origin unknown, skipping origin check on received message', event);
243
+ }
244
+
231
245
  log(`message received of type "${event.type}"`, event);
232
246
 
233
247
  const handlers: Record<string, Function> = {