@ordergroove/offers 2.49.0 → 2.49.1-alpha-PR-1517-4.76
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ordergroove/offers",
|
|
3
|
-
"version": "2.49.
|
|
3
|
+
"version": "2.49.1-alpha-PR-1517-4.76+5e3f5ef73",
|
|
4
4
|
"description": "offer state component",
|
|
5
5
|
"author": "Eugenio Lattanzio <eugenio63@gmail.com>",
|
|
6
6
|
"homepage": "https://github.com/ordergroove/plush-toys#readme",
|
|
@@ -50,5 +50,5 @@
|
|
|
50
50
|
"@ordergroove/offers-templates": "^0.10.4",
|
|
51
51
|
"@types/lodash.memoize": "^4.1.9"
|
|
52
52
|
},
|
|
53
|
-
"gitHead": "
|
|
53
|
+
"gitHead": "5e3f5ef73dcd7f5843a3db07236c1cf37cfa2140"
|
|
54
54
|
}
|
|
@@ -2,6 +2,6 @@ import { STATIC_HOST } from './core/constants';
|
|
|
2
2
|
|
|
3
3
|
const mainJs = document.createElement('script');
|
|
4
4
|
mainJs.setAttribute('id', `mock-main-js`);
|
|
5
|
-
mainJs.setAttribute('src', `http://${STATIC_HOST}`);
|
|
5
|
+
mainJs.setAttribute('src', `http://${STATIC_HOST}/test-merchant/main.js`);
|
|
6
6
|
mainJs.dataset.shopifySellingPlans = true;
|
|
7
7
|
document.head.appendChild(mainJs);
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import fetchMock from 'fetch-mock';
|
|
2
|
+
import { authorizeShopifyCustomer } from '../shopifyBootstrap';
|
|
3
|
+
import { AUTHORIZE, UNAUTHORIZED, STATIC_HOST } from '../../core/constants';
|
|
4
|
+
|
|
5
|
+
// init-shopify-tests.js inserts this script before any test runs
|
|
6
|
+
const mainJsScript = document.querySelector(`script[src^="http://${STATIC_HOST}"]`);
|
|
7
|
+
|
|
8
|
+
const MERCHANT_ID = 'test-merchant';
|
|
9
|
+
const AUTH_ENDPOINT = '/apps/subscriptions/auth/';
|
|
10
|
+
|
|
11
|
+
describe('authorizeShopifyCustomer', () => {
|
|
12
|
+
let store;
|
|
13
|
+
|
|
14
|
+
beforeEach(() => {
|
|
15
|
+
store = { dispatch: jasmine.createSpy('dispatch') };
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
afterEach(() => {
|
|
19
|
+
delete mainJsScript.dataset.customer;
|
|
20
|
+
// expire the og_auth cookie; just setting to empty string will be ignored
|
|
21
|
+
document.cookie = 'og_auth=; expires=Thu, 01 Jan 1970 00:00:01 GMT; path=/';
|
|
22
|
+
fetchMock.clearHistory();
|
|
23
|
+
fetchMock.removeRoutes().unmockGlobal();
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it('fetches OG signature, sets og_auth cookie, and dispatches AUTHORIZE when encoded customer is on main.js script', async () => {
|
|
27
|
+
// The Shopify integration encodes customer data as btoa("id|timestamp|signature|email")
|
|
28
|
+
// on the data-customer attribute of the main.js script tag.
|
|
29
|
+
const shopifyCustomerId = 'shopify-cust-42';
|
|
30
|
+
const shopifyTimestamp = '1700000000';
|
|
31
|
+
const shopifySignature = 'shopify-raw-sig';
|
|
32
|
+
|
|
33
|
+
mainJsScript.dataset.customer = btoa(
|
|
34
|
+
`${shopifyCustomerId}|${shopifyTimestamp}|${shopifySignature}|test@example.com`
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
// OG's auth endpoint returns a signed customer ID embedded between marker strings.
|
|
38
|
+
const ogCustomerId = 'og-cust-99';
|
|
39
|
+
const ogTimestamp = 1700000099;
|
|
40
|
+
const ogSignature = 'og-server-sig';
|
|
41
|
+
|
|
42
|
+
fetchMock.route(
|
|
43
|
+
`${AUTH_ENDPOINT}?customer=${shopifyCustomerId}&customer_signature=${shopifySignature}&customer_timestamp=${shopifyTimestamp}`,
|
|
44
|
+
`<main>
|
|
45
|
+
og_auth_begin
|
|
46
|
+
{
|
|
47
|
+
"customerId": "${ogCustomerId}",
|
|
48
|
+
"timestamp": ${ogTimestamp},
|
|
49
|
+
"signature": "${ogSignature}"
|
|
50
|
+
}
|
|
51
|
+
og_auth_end
|
|
52
|
+
</main>`,
|
|
53
|
+
{ method: 'GET' }
|
|
54
|
+
);
|
|
55
|
+
fetchMock.mockGlobal();
|
|
56
|
+
|
|
57
|
+
await authorizeShopifyCustomer({ store });
|
|
58
|
+
|
|
59
|
+
const binarySignature = btoa(ogSignature);
|
|
60
|
+
|
|
61
|
+
expect(document.cookie).toContain(`og_auth=${ogCustomerId}|${ogTimestamp}|${binarySignature}`);
|
|
62
|
+
|
|
63
|
+
expect(store.dispatch).toHaveBeenCalledWith({
|
|
64
|
+
type: AUTHORIZE,
|
|
65
|
+
payload: {
|
|
66
|
+
public_id: MERCHANT_ID,
|
|
67
|
+
sig_field: ogCustomerId,
|
|
68
|
+
ts: ogTimestamp,
|
|
69
|
+
sig: binarySignature
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
it('reuses existing og_auth cookie and dispatches AUTHORIZE without fetching', async () => {
|
|
75
|
+
mainJsScript.dataset.customer = btoa('shopify-cust-42|1700000000|shopify-raw-sig|test@example.com');
|
|
76
|
+
|
|
77
|
+
const cachedCustomerId = 'cached-cust';
|
|
78
|
+
const cachedTimestamp = 1699999999;
|
|
79
|
+
const cachedSig = btoa('cached-server-sig');
|
|
80
|
+
document.cookie = `og_auth=${cachedCustomerId}|${cachedTimestamp}|${cachedSig}; path=/`;
|
|
81
|
+
|
|
82
|
+
fetchMock.mockGlobal(); // no routes — any fetch call would throw
|
|
83
|
+
|
|
84
|
+
await authorizeShopifyCustomer({ store });
|
|
85
|
+
|
|
86
|
+
expect(fetchMock.callHistory.called()).toBe(false);
|
|
87
|
+
expect(store.dispatch).toHaveBeenCalledWith({
|
|
88
|
+
type: AUTHORIZE,
|
|
89
|
+
payload: {
|
|
90
|
+
public_id: MERCHANT_ID,
|
|
91
|
+
sig_field: cachedCustomerId,
|
|
92
|
+
ts: cachedTimestamp,
|
|
93
|
+
sig: cachedSig
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
it('clears og_auth cookie and does not dispatch when no customer is present', async () => {
|
|
99
|
+
document.cookie = 'og_auth=existing-value; path=/';
|
|
100
|
+
expect(document.cookie).toContain('og_auth=existing-value');
|
|
101
|
+
|
|
102
|
+
await authorizeShopifyCustomer({ store });
|
|
103
|
+
|
|
104
|
+
expect(document.cookie).not.toContain('og_auth=');
|
|
105
|
+
expect(store.dispatch).toHaveBeenCalledWith({
|
|
106
|
+
type: UNAUTHORIZED,
|
|
107
|
+
payload: jasmine.any(String)
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
});
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { authorize } from '../core/actions';
|
|
1
|
+
import { authorize, unauthorized } from '../core/actions';
|
|
2
2
|
import { clearCookie, getCookieValue, getMainJs, resolveEnvAndMerchant } from '../core/utils';
|
|
3
3
|
|
|
4
4
|
const SHOPIFY_OG_AUTH_ENDPOINT = '/apps/subscriptions/auth/';
|
|
@@ -93,6 +93,8 @@ export async function authorizeShopifyCustomer({ store }) {
|
|
|
93
93
|
}
|
|
94
94
|
} else {
|
|
95
95
|
clearCookie('og_auth');
|
|
96
|
+
// after clearing the cookie, we need to make sure the store clears its own auth state
|
|
97
|
+
store.dispatch(unauthorized('No customer found'));
|
|
96
98
|
}
|
|
97
99
|
}
|
|
98
100
|
/**
|
|
@@ -138,7 +140,7 @@ export async function getOrCreateAuthCookie(customer: OgShopifyConfigCustomer) {
|
|
|
138
140
|
const ogToday = new Date();
|
|
139
141
|
const binarySignature = btoa(signature);
|
|
140
142
|
ogToday.setTime(ogToday.getTime() + 2 * 60 * 60 * 1000);
|
|
141
|
-
const value = `${customerId}|${timestamp}|${binarySignature}
|
|
142
|
-
document.cookie = `og_auth=${value};secure;path=/`;
|
|
143
|
+
const value = `${customerId}|${timestamp}|${binarySignature}`;
|
|
144
|
+
document.cookie = `og_auth=${value};expires=${ogToday.toUTCString()};secure;path=/`;
|
|
143
145
|
return value;
|
|
144
146
|
}
|