From 6612efd8e65050f82e207debe98abdbf6d932ecd Mon Sep 17 00:00:00 2001 From: Steve Mask Date: Sat, 10 Jun 2023 15:29:49 -0400 Subject: [PATCH 1/5] feat(venmo): allow trusted domains --- src/child/props.js | 11 +++---- src/component/props.js | 1 + src/parent/parent.js | 11 +++---- test/tests/props.js | 67 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 80 insertions(+), 10 deletions(-) diff --git a/src/child/props.js b/src/child/props.js index c5c4588e..d305bd81 100644 --- a/src/child/props.js +++ b/src/child/props.js @@ -82,11 +82,12 @@ export function normalizeChildProps( for (const key of Object.keys(props)) { const prop = propsDef[key]; - if ( - prop && - prop.sameDomain && - (origin !== getDomain(window) || !isSameDomain(parentComponentWindow)) - ) { + const trustedChild: boolean = + prop && prop.trustedDomains && prop.trustedDomains.length > 0 + ? prop.trustedDomains.indexOf(getDomain(window)) !== -1 + : origin === getDomain(window) || isSameDomain(parentComponentWindow); + + if (prop && prop.sameDomain && !trustedChild) { continue; } diff --git a/src/component/props.js b/src/component/props.js index ff1adf55..5a01a8fa 100644 --- a/src/component/props.js +++ b/src/component/props.js @@ -191,6 +191,7 @@ export type PropDefinitionType, X> = {| validate?: ({| value: T, props: PropsType

|}) => void, sameDomain?: boolean, serialization?: $Values, + trustedDomains?: $ReadOnlyArray, |}; export type BOOLEAN_DEFINITION_TYPE = typeof PROP_TYPE.BOOLEAN; diff --git a/src/parent/parent.js b/src/parent/parent.js index bd92ad29..7f4188bc 100644 --- a/src/parent/parent.js +++ b/src/parent/parent.js @@ -378,11 +378,12 @@ export function parentComponent({ continue; } - if ( - prop && - prop.sameDomain && - !matchDomain(initialChildDomain, getDomain(window)) - ) { + const trustedChild: boolean = + prop && prop.trustedDomains && prop.trustedDomains.length > 0 + ? prop.trustedDomains.indexOf(initialChildDomain) !== -1 + : matchDomain(initialChildDomain, getDomain(window)); + + if (prop && prop.sameDomain && !trustedChild) { continue; } diff --git a/test/tests/props.js b/test/tests/props.js index 0f955359..d489e536 100644 --- a/test/tests/props.js +++ b/test/tests/props.js @@ -813,6 +813,73 @@ describe("zoid props cases", () => { }); }); + it("should pass a trustedDomain prop and have it populate on the child", () => { + return wrapPromise(({ expect }) => { + window.__component__ = () => { + return zoid.create({ + tag: "test-trusteddomain-prop-passed", + url: "mock://www.child.com/base/test/windows/child/index.htm", + domain: ["mock://www.child.com"], + props: { + foo: { + type: "string", + trustedDomains: ["mock://www.child.com"], + }, + }, + }); + }; + + const component = window.__component__(); + const instance = component({ + foo: "bar", + passProp: expect("passProp", (val) => { + if (!val) { + throw new Error(`Expected val to be passed`); + } + }), + run: () => ` + window.xprops.passProp(window.xprops.foo); + `, + }); + + return instance.render(getBody()); + }); + }); + + it("should pass a trustedDomain and sameDomain=true prop and have it populate on the child", () => { + return wrapPromise(({ expect }) => { + window.__component__ = () => { + return zoid.create({ + tag: "test-samedomain-trusteddomain-prop-passed", + url: "mock://www.child.com/base/test/windows/child/index.htm", + domain: ["mock://www.child.com"], + props: { + foo: { + type: "string", + sameDomain: true, + trustedDomains: ["mock://www.child.com"], + }, + }, + }); + }; + + const component = window.__component__(); + const instance = component({ + foo: "bar", + passProp: expect("passProp", (val) => { + if (!val) { + throw new Error(`Expected val to be passed`); + } + }), + run: () => ` + window.xprops.passProp(window.xprops.foo); + `, + }); + + return instance.render(getBody()); + }); + }); + it("should alias a prop and have it copy correctly", () => { return wrapPromise(({ expect }) => { window.__component__ = () => { From 03f9b3f77f1b8192bf870be3253ef2caf6026ca6 Mon Sep 17 00:00:00 2001 From: Steven Mask Date: Mon, 12 Jun 2023 11:37:23 -0400 Subject: [PATCH 2/5] chore(rebase): update commit messages --- src/child/props.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/child/props.js b/src/child/props.js index d305bd81..e1907747 100644 --- a/src/child/props.js +++ b/src/child/props.js @@ -84,7 +84,7 @@ export function normalizeChildProps( const trustedChild: boolean = prop && prop.trustedDomains && prop.trustedDomains.length > 0 - ? prop.trustedDomains.indexOf(getDomain(window)) !== -1 + ? prop.trustedDomains.includes(getDomain(window)) : origin === getDomain(window) || isSameDomain(parentComponentWindow); if (prop && prop.sameDomain && !trustedChild) { From 608a2a6b1b6f591f6dd4178c3f031d21c8d8423a Mon Sep 17 00:00:00 2001 From: Steven Mask Date: Mon, 12 Jun 2023 11:37:37 -0400 Subject: [PATCH 3/5] chore(rebase): update commit message --- src/parent/parent.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/parent/parent.js b/src/parent/parent.js index 7f4188bc..1583e2c6 100644 --- a/src/parent/parent.js +++ b/src/parent/parent.js @@ -380,7 +380,7 @@ export function parentComponent({ const trustedChild: boolean = prop && prop.trustedDomains && prop.trustedDomains.length > 0 - ? prop.trustedDomains.indexOf(initialChildDomain) !== -1 + ? prop.trustedDomains.includes(initialChildDomain) : matchDomain(initialChildDomain, getDomain(window)); if (prop && prop.sameDomain && !trustedChild) { From 2cecf7cb9ecca3ba0f8fef6f00a32c450e7216c7 Mon Sep 17 00:00:00 2001 From: Steve Mask Date: Mon, 12 Jun 2023 12:33:51 -0400 Subject: [PATCH 4/5] chore(domain): remove domain config from tests as not required when url is same domain --- test/tests/props.js | 88 ++++++++++++++++++--------------------------- 1 file changed, 35 insertions(+), 53 deletions(-) diff --git a/test/tests/props.js b/test/tests/props.js index d489e536..a1ee8e32 100644 --- a/test/tests/props.js +++ b/test/tests/props.js @@ -20,7 +20,6 @@ describe("zoid props cases", () => { return zoid.create({ tag: "test-prop-value", url: "mock://www.child.com/base/test/windows/child/index.htm", - domain: "mock://www.child.com", props: { foo: { type: "string", @@ -60,7 +59,6 @@ describe("zoid props cases", () => { return zoid.create({ tag: "test-prop-value-container", url: "mock://www.child.com/base/test/windows/child/index.htm", - domain: "mock://www.child.com", props: { foo: { type: "number", @@ -103,7 +101,6 @@ describe("zoid props cases", () => { return zoid.create({ tag: "test-prop-value-container-url-param", url: "mock://www.child.com/base/test/windows/child/index.htm", - domain: "mock://www.child.com", props: { foo: { type: "number", @@ -145,7 +142,6 @@ describe("zoid props cases", () => { return zoid.create({ tag: "test-prop-value-container-url-param-element-not-ready", url: "mock://www.child.com/base/test/windows/child/index.htm", - domain: "mock://www.child.com", props: { foo: { type: "number", @@ -201,7 +197,6 @@ describe("zoid props cases", () => { return zoid.create({ tag: "test-update-prop", url: "mock://www.child.com/base/test/windows/child/index.htm", - domain: "mock://www.child.com", }); }; @@ -234,7 +229,6 @@ describe("zoid props cases", () => { return zoid.create({ tag: "test-update-different-prop", url: "mock://www.child.com/base/test/windows/child/index.htm", - domain: "mock://www.child.com", }); }; @@ -269,7 +263,6 @@ describe("zoid props cases", () => { return zoid.create({ tag: "test-update-decorated-different-prop", url: "mock://www.child.com/base/test/windows/child/index.htm", - domain: "mock://www.child.com", props: { baz: { @@ -322,7 +315,6 @@ describe("zoid props cases", () => { return zoid.create({ tag: "test-prop-input-value-passing", url: "mock://www.child.com/base/test/windows/child/index.htm", - domain: "mock://www.child.com", props: { account: { type: "string", @@ -364,7 +356,6 @@ describe("zoid props cases", () => { return zoid.create({ tag: "changing-decorated-function-signature", url: "mock://www.child.com/base/test/windows/child/index.htm", - domain: "mock://www.child.com", props: { onSuccess: { type: "function", @@ -407,7 +398,6 @@ describe("zoid props cases", () => { return zoid.create({ tag: "test-update-default-prop", url: "mock://www.child.com/base/test/windows/child/index.htm", - domain: "mock://www.child.com", props: { meep: { type: "function", @@ -444,7 +434,6 @@ describe("zoid props cases", () => { return zoid.create({ tag: "test-update-value-prop", url: "mock://www.child.com/base/test/windows/child/index.htm", - domain: "mock://www.child.com", props: { meep: { type: "function", @@ -485,7 +474,6 @@ describe("zoid props cases", () => { return zoid.create({ tag: "test-string-prop", url: "mock://www.child.com/base/test/windows/child/index.htm", - domain: "mock://www.child.com", }); }; @@ -514,7 +502,6 @@ describe("zoid props cases", () => { return zoid.create({ tag: "test-number-prop", url: "mock://www.child.com/base/test/windows/child/index.htm", - domain: "mock://www.child.com", }); }; @@ -543,7 +530,6 @@ describe("zoid props cases", () => { return zoid.create({ tag: "test-boolean-prop", url: "mock://www.child.com/base/test/windows/child/index.htm", - domain: "mock://www.child.com", }); }; @@ -579,7 +565,6 @@ describe("zoid props cases", () => { return zoid.create({ tag: "test-array-prop", url: "mock://www.child.com/base/test/windows/child/index.htm", - domain: "mock://www.child.com", }); }; @@ -645,7 +630,6 @@ describe("zoid props cases", () => { return zoid.create({ tag: "test-object-prop", url: "mock://www.child.com/base/test/windows/child/index.htm", - domain: "mock://www.child.com", }); }; @@ -702,7 +686,6 @@ describe("zoid props cases", () => { return zoid.create({ tag: "test-function-prop", url: "mock://www.child.com/base/test/windows/child/index.htm", - domain: "mock://www.child.com", }); }; @@ -730,7 +713,6 @@ describe("zoid props cases", () => { return zoid.create({ tag: "test-required-prop", url: "mock://www.child.com/base/test/windows/child/index.htm", - domain: "mock://www.child.com", props: { foo: { type: "string", @@ -753,7 +735,6 @@ describe("zoid props cases", () => { return zoid.create({ tag: "test-samedomain-prop", url: "mock://www.child.com/base/test/windows/child/index.htm", - domain: "mock://www.child.com", props: { foo: { type: "string", @@ -786,7 +767,6 @@ describe("zoid props cases", () => { return zoid.create({ tag: "test-samedomain-prop-passed", url: "mock://www.child.com/base/test/windows/child/index.htm", - domain: "mock://www.child.com", props: { foo: { type: "string", @@ -819,11 +799,10 @@ describe("zoid props cases", () => { return zoid.create({ tag: "test-trusteddomain-prop-passed", url: "mock://www.child.com/base/test/windows/child/index.htm", - domain: ["mock://www.child.com"], props: { foo: { type: "string", - trustedDomains: ["mock://www.child.com"], + trustedDomains: ["mock://venmo.com"], }, }, }); @@ -838,6 +817,40 @@ describe("zoid props cases", () => { } }), run: () => ` + window.location = "mock://venmo.com"; + window.xprops.passProp(window.xprops.foo); + `, + }); + + return instance.render(getBody()); + }); + }); + + it("should pass a trustedDomain prop and have it not populate on the child if no match", () => { + return wrapPromise(({ expect }) => { + window.__component__ = () => { + return zoid.create({ + tag: "test-trusteddomain-prop-not-passed", + url: "mock://www.child.com/base/test/windows/child/index.htm", + props: { + foo: { + type: "string", + trustedDomains: ["mock://www.other.com"], + }, + }, + }); + }; + + const component = window.__component__(); + const instance = component({ + foo: "bar", + passProp: expect("passProp", (val) => { + if (val) { + throw new Error(`Expected val to not be passed`); + } + }), + run: () => ` + window.location = "mock://venmo.com"; window.xprops.passProp(window.xprops.foo); `, }); @@ -852,7 +865,6 @@ describe("zoid props cases", () => { return zoid.create({ tag: "test-samedomain-trusteddomain-prop-passed", url: "mock://www.child.com/base/test/windows/child/index.htm", - domain: ["mock://www.child.com"], props: { foo: { type: "string", @@ -886,7 +898,6 @@ describe("zoid props cases", () => { return zoid.create({ tag: "test-alias-prop", url: "mock://www.child.com/base/test/windows/child/index.htm", - domain: "mock://www.child.com", props: { foo: { type: "function", @@ -914,7 +925,6 @@ describe("zoid props cases", () => { return zoid.create({ tag: "test-alias-reverse-prop", url: "mock://www.child.com/base/test/windows/child/index.htm", - domain: "mock://www.child.com", props: { foo: { type: "function", @@ -942,7 +952,6 @@ describe("zoid props cases", () => { return zoid.create({ tag: "test-props-query-param", url: "mock://www.child.com/base/test/windows/child/index.htm", - domain: "mock://www.child.com", props: { fooProp: { type: "string", @@ -1044,7 +1053,6 @@ describe("zoid props cases", () => { return zoid.create({ tag: "test-props-boolean-query-param", url: "mock://www.child.com/base/test/windows/child/index.htm", - domain: "mock://www.child.com", props: { trueProp: { type: "boolean", @@ -1099,7 +1107,6 @@ describe("zoid props cases", () => { return zoid.create({ tag: "test-promise-props-query-param", url: "mock://www.child.com/base/test/windows/child/index.htm", - domain: "mock://www.child.com", props: { promiseProp: { type: "function", @@ -1151,7 +1158,6 @@ describe("zoid props cases", () => { return zoid.create({ tag: "test-promise-props-query-param-empty-string", url: "mock://www.child.com/base/test/windows/child/index.htm", - domain: "mock://www.child.com", props: { fooBar: { type: "string", @@ -1187,7 +1193,6 @@ describe("zoid props cases", () => { return zoid.create({ tag: "test-promise-props-query-param-empty-string-null-decorator", url: "mock://www.child.com/base/test/windows/child/index.htm", - domain: "mock://www.child.com", props: { fooBar: { type: "string", @@ -1230,7 +1235,6 @@ describe("zoid props cases", () => { return zoid.create({ tag: "test-update-prop-destroy-component", url: "mock://www.child.com/base/test/windows/child/index.htm", - domain: "mock://www.child.com", }); }; @@ -1292,7 +1296,6 @@ describe("zoid props cases", () => { return zoid.create({ tag: "test-update-prop-delay", url: "mock://www.child.com/base/test/windows/child/index.htm", - domain: "mock://www.child.com", }); }; @@ -1325,7 +1328,6 @@ describe("zoid props cases", () => { return zoid.create({ tag: "test-prop-value-derived-from-props", url: "mock://www.child.com/base/test/windows/child/index.htm", - domain: "mock://www.child.com", props: { foo: { type: "string", @@ -1367,7 +1369,6 @@ describe("zoid props cases", () => { return zoid.create({ tag: "test-prop-value-derived-from-props-with-same-prop", url: "mock://www.child.com/base/test/windows/child/index.htm", - domain: "mock://www.child.com", props: { bar: { type: "string", @@ -1406,7 +1407,6 @@ describe("zoid props cases", () => { return zoid.create({ tag: "test-prop-value-undefined-error", url: "mock://www.child.com/base/test/windows/child/index.htm", - domain: "mock://www.child.com", props: { foo: { type: "string", @@ -1440,7 +1440,6 @@ describe("zoid props cases", () => { zoid.create({ tag: "test-prop-value-required-default", url: "mock://www.child.com/base/test/windows/child/index.htm", - domain: "mock://www.child.com", props: { foo: { type: "string", @@ -1465,7 +1464,6 @@ describe("zoid props cases", () => { return zoid.create({ tag: "test-update-decorated-multiple-times", url: "mock://www.child.com/base/test/windows/child/index.htm", - domain: "mock://www.child.com", props: { baz: { @@ -1521,7 +1519,6 @@ describe("zoid props cases", () => { return zoid.create({ tag: "test-update-decorated-multiple-times-updated-multiple-times", url: "mock://www.child.com/base/test/windows/child/index.htm", - domain: "mock://www.child.com", props: { baz: { @@ -1595,7 +1592,6 @@ describe("zoid props cases", () => { return zoid.create({ tag: "test-update-decorated-multiple-times-multiple-instances", url: "mock://www.child.com/base/test/windows/child/index.htm", - domain: "mock://www.child.com", props: { baz: { @@ -1659,7 +1655,6 @@ describe("zoid props cases", () => { return zoid.create({ tag: "test-update-decorated-multiple-times-multiple-instances-updated-multiple-times", url: "mock://www.child.com/base/test/windows/child/index.htm", - domain: "mock://www.child.com", props: { baz: { @@ -1745,7 +1740,6 @@ describe("zoid props cases", () => { return zoid.create({ tag: "test-value-passed-prop", url: "mock://www.child.com/base/test/windows/child/index.htm", - domain: "mock://www.child.com", props: { foo: { @@ -1801,7 +1795,6 @@ describe("zoid props cases", () => { return zoid.create({ tag: "test-default-passed-prop", url: "mock://www.child.com/base/test/windows/child/index.htm", - domain: "mock://www.child.com", props: { foo: { @@ -1857,7 +1850,6 @@ describe("zoid props cases", () => { return zoid.create({ tag: "test-decorated-passed-prop", url: "mock://www.child.com/base/test/windows/child/index.htm", - domain: "mock://www.child.com", props: { foo: { @@ -1904,7 +1896,6 @@ describe("zoid props cases", () => { return zoid.create({ tag: "test-decorated-alias-prop", url: "mock://www.child.com/base/test/windows/child/index.htm", - domain: "mock://www.child.com", props: { foo: { @@ -1955,7 +1946,6 @@ describe("zoid props cases", () => { return zoid.create({ tag: "test-decorated-reverse-alias-prop", url: "mock://www.child.com/base/test/windows/child/index.htm", - domain: "mock://www.child.com", props: { foo: { @@ -2009,7 +1999,6 @@ describe("zoid props cases", () => { return zoid.create({ tag: "test-decorated-value-prop", url: "mock://www.child.com/base/test/windows/child/index.htm", - domain: "mock://www.child.com", props: { foo: { @@ -2059,7 +2048,6 @@ describe("zoid props cases", () => { return zoid.create({ tag: "test-decorated-self-value-prop", url: "mock://www.child.com/base/test/windows/child/index.htm", - domain: "mock://www.child.com", props: { baz: { @@ -2101,7 +2089,6 @@ describe("zoid props cases", () => { return zoid.create({ tag: "test-decorated-default-prop", url: "mock://www.child.com/base/test/windows/child/index.htm", - domain: "mock://www.child.com", props: { foo: { @@ -2151,7 +2138,6 @@ describe("zoid props cases", () => { return zoid.create({ tag: "test-decorated-self-default-prop", url: "mock://www.child.com/base/test/windows/child/index.htm", - domain: "mock://www.child.com", props: { baz: { @@ -2193,7 +2179,6 @@ describe("zoid props cases", () => { return zoid.create({ tag: "test-decorate-diff-signature-props", url: "mock://www.child.com/base/test/windows/child/index.htm", - domain: "mock://www.child.com", props: { foo: { @@ -2244,7 +2229,6 @@ describe("zoid props cases", () => { return zoid.create({ tag: "test-decorate-diff-signature-value", url: "mock://www.child.com/base/test/windows/child/index.htm", - domain: "mock://www.child.com", props: { foo: { @@ -2293,7 +2277,6 @@ describe("zoid props cases", () => { return zoid.create({ tag: "test-value-diff-signature-props", url: "mock://www.child.com/base/test/windows/child/index.htm", - domain: "mock://www.child.com", props: { foo: { @@ -2344,7 +2327,6 @@ describe("zoid props cases", () => { return zoid.create({ tag: "test-prop-value-get-other-props", url: "mock://www.child.com/base/test/windows/child/index.htm", - domain: "mock://www.child.com", props: { superpropfunc: { From 6e7f70a369f9d954804477bd894514df17d19417 Mon Sep 17 00:00:00 2001 From: Steve Mask Date: Mon, 12 Jun 2023 13:10:53 -0400 Subject: [PATCH 5/5] chore(test): negative test case for trustedDomains --- src/child/props.js | 6 ++++++ src/parent/parent.js | 6 ++++++ test/tests/domain.js | 4 ++-- test/tests/props.js | 4 +--- 4 files changed, 15 insertions(+), 5 deletions(-) diff --git a/src/child/props.js b/src/child/props.js index e1907747..335a2fc3 100644 --- a/src/child/props.js +++ b/src/child/props.js @@ -87,10 +87,16 @@ export function normalizeChildProps( ? prop.trustedDomains.includes(getDomain(window)) : origin === getDomain(window) || isSameDomain(parentComponentWindow); + // let trustedDomains override sameDomain prop if (prop && prop.sameDomain && !trustedChild) { continue; } + // sameDomain was not set and trusted domains must match + if (prop && prop.trustedDomains && !trustedChild) { + continue; + } + // $FlowFixMe const value = normalizeChildProp(propsDef, props, key, props[key], helpers); diff --git a/src/parent/parent.js b/src/parent/parent.js index 1583e2c6..ba48e244 100644 --- a/src/parent/parent.js +++ b/src/parent/parent.js @@ -383,10 +383,16 @@ export function parentComponent({ ? prop.trustedDomains.includes(initialChildDomain) : matchDomain(initialChildDomain, getDomain(window)); + // let trustedDomains override sameDomain prop if (prop && prop.sameDomain && !trustedChild) { continue; } + // sameDomain was not set and trusted domains must match + if (prop && prop.trustedDomains && !trustedChild) { + continue; + } + result[key] = props[key]; } diff --git a/test/tests/domain.js b/test/tests/domain.js index 38389de9..cb414890 100644 --- a/test/tests/domain.js +++ b/test/tests/domain.js @@ -68,7 +68,7 @@ describe("parent domain check", () => { return component().render(getBody()); }); - it("allowedParentDomains is specified as a regex and parent domian match", () => { + it("allowedParentDomains is specified as a regex and parent domain match", () => { window.__component__ = () => { return zoid.create({ tag: "test-parent-domain-regex", @@ -163,7 +163,7 @@ describe("parent domain check", () => { }); }); - it("xprops.getParentDomain should pass the correct domain", () => { + it("xprops.getParent should pass the correct domain", () => { return wrapPromise(({ expect }) => { window.__component__ = () => { return zoid.create({ diff --git a/test/tests/props.js b/test/tests/props.js index a1ee8e32..6c4324e5 100644 --- a/test/tests/props.js +++ b/test/tests/props.js @@ -802,7 +802,7 @@ describe("zoid props cases", () => { props: { foo: { type: "string", - trustedDomains: ["mock://venmo.com"], + trustedDomains: ["mock://www.child.com"], }, }, }); @@ -817,7 +817,6 @@ describe("zoid props cases", () => { } }), run: () => ` - window.location = "mock://venmo.com"; window.xprops.passProp(window.xprops.foo); `, }); @@ -850,7 +849,6 @@ describe("zoid props cases", () => { } }), run: () => ` - window.location = "mock://venmo.com"; window.xprops.passProp(window.xprops.foo); `, });