@shopify/shopify-app-remix 2.2.0 → 2.4.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/build/cjs/server/adapters/node/index.js +1 -0
- package/build/cjs/server/authenticate/admin/authenticate.js +17 -14
- package/build/cjs/server/authenticate/admin/billing/cancel.js +1 -2
- package/build/cjs/server/authenticate/admin/billing/request.js +0 -1
- package/build/cjs/server/authenticate/admin/billing/require.js +1 -2
- package/build/cjs/server/authenticate/admin/helpers/create-admin-api-context.js +2 -5
- package/build/cjs/server/authenticate/admin/helpers/handle-client-error.js +8 -4
- package/build/cjs/server/authenticate/admin/helpers/redirect-to-bounce-page.js +4 -2
- package/build/cjs/server/authenticate/admin/helpers/redirect.js +1 -5
- package/build/cjs/server/authenticate/admin/helpers/trigger-after-auth-hook.js +2 -2
- package/build/cjs/server/authenticate/admin/strategies/auth-code-flow.js +37 -13
- package/build/cjs/server/authenticate/admin/strategies/token-exchange.js +155 -0
- package/build/cjs/server/authenticate/const.js +4 -0
- package/build/cjs/server/authenticate/helpers/idempotent-promise-handler.js +40 -0
- package/build/cjs/server/authenticate/helpers/respond-to-invalid-session-token.js +33 -0
- package/build/cjs/server/authenticate/login/login.js +5 -1
- package/build/cjs/server/authenticate/public/checkout/authenticate.js +1 -0
- package/build/cjs/server/authenticate/webhooks/authenticate.js +1 -2
- package/build/cjs/server/authenticate/webhooks/register.js +16 -0
- package/build/cjs/server/clients/admin/graphql.js +5 -12
- package/build/cjs/server/clients/storefront/factory.js +5 -12
- package/build/cjs/server/shopify-app.js +12 -6
- package/build/cjs/server/version.js +1 -1
- package/build/ts/react/components/AppProvider/AppProvider.js +1 -1
- package/build/ts/react/components/AppProvider/AppProvider.js.map +1 -1
- package/build/ts/server/__test-helpers/const.d.ts +2 -1
- package/build/ts/server/__test-helpers/const.d.ts.map +1 -1
- package/build/ts/server/__test-helpers/const.js +3 -2
- package/build/ts/server/__test-helpers/const.js.map +1 -1
- package/build/ts/server/__test-helpers/expect-admin-api-client.d.ts.map +1 -1
- package/build/ts/server/__test-helpers/expect-admin-api-client.js +2 -2
- package/build/ts/server/__test-helpers/expect-admin-api-client.js.map +1 -1
- package/build/ts/server/__test-helpers/expect-document-request-headers.js.map +1 -1
- package/build/ts/server/__test-helpers/expect-exit-iframe.js.map +1 -1
- package/build/ts/server/__test-helpers/expect-storefront-api-client.js +1 -1
- package/build/ts/server/__test-helpers/expect-storefront-api-client.js.map +1 -1
- package/build/ts/server/__test-helpers/get-thrown-response.js.map +1 -1
- package/build/ts/server/__test-helpers/request-mock.d.ts.map +1 -1
- package/build/ts/server/__test-helpers/request-mock.js +1 -1
- package/build/ts/server/__test-helpers/request-mock.js.map +1 -1
- package/build/ts/server/__test-helpers/setup-valid-session.d.ts +1 -1
- package/build/ts/server/__test-helpers/setup-valid-session.d.ts.map +1 -1
- package/build/ts/server/__test-helpers/setup-valid-session.js +5 -5
- package/build/ts/server/__test-helpers/setup-valid-session.js.map +1 -1
- package/build/ts/server/__test-helpers/test-config.d.ts +2 -1
- package/build/ts/server/__test-helpers/test-config.d.ts.map +1 -1
- package/build/ts/server/__test-helpers/test-config.js +1 -0
- package/build/ts/server/__test-helpers/test-config.js.map +1 -1
- package/build/ts/server/adapters/node/index.js.map +1 -1
- package/build/ts/server/authenticate/admin/authenticate.d.ts +7 -1
- package/build/ts/server/authenticate/admin/authenticate.d.ts.map +1 -1
- package/build/ts/server/authenticate/admin/authenticate.js +14 -14
- package/build/ts/server/authenticate/admin/authenticate.js.map +1 -1
- package/build/ts/server/authenticate/admin/billing/request.js.map +1 -1
- package/build/ts/server/authenticate/admin/helpers/create-admin-api-context.d.ts +2 -2
- package/build/ts/server/authenticate/admin/helpers/create-admin-api-context.d.ts.map +1 -1
- package/build/ts/server/authenticate/admin/helpers/create-admin-api-context.js +2 -5
- package/build/ts/server/authenticate/admin/helpers/create-admin-api-context.js.map +1 -1
- package/build/ts/server/authenticate/admin/helpers/ensure-session-token-search-param-if-required.js.map +1 -1
- package/build/ts/server/authenticate/admin/helpers/handle-client-error.d.ts +2 -5
- package/build/ts/server/authenticate/admin/helpers/handle-client-error.d.ts.map +1 -1
- package/build/ts/server/authenticate/admin/helpers/handle-client-error.js +6 -5
- package/build/ts/server/authenticate/admin/helpers/handle-client-error.js.map +1 -1
- package/build/ts/server/authenticate/admin/helpers/redirect-to-bounce-page.d.ts.map +1 -1
- package/build/ts/server/authenticate/admin/helpers/redirect-to-bounce-page.js +4 -2
- package/build/ts/server/authenticate/admin/helpers/redirect-to-bounce-page.js.map +1 -1
- package/build/ts/server/authenticate/admin/helpers/redirect-with-exitiframe.js.map +1 -1
- package/build/ts/server/authenticate/admin/helpers/redirect.js +0 -3
- package/build/ts/server/authenticate/admin/helpers/redirect.js.map +1 -1
- package/build/ts/server/authenticate/admin/helpers/render-app-bridge.js.map +1 -1
- package/build/ts/server/authenticate/admin/helpers/trigger-after-auth-hook.d.ts +2 -1
- package/build/ts/server/authenticate/admin/helpers/trigger-after-auth-hook.d.ts.map +1 -1
- package/build/ts/server/authenticate/admin/helpers/trigger-after-auth-hook.js +2 -2
- package/build/ts/server/authenticate/admin/helpers/trigger-after-auth-hook.js.map +1 -1
- package/build/ts/server/authenticate/admin/helpers/validate-shop-and-host-params.js.map +1 -1
- package/build/ts/server/authenticate/admin/strategies/auth-code-flow.d.ts +4 -2
- package/build/ts/server/authenticate/admin/strategies/auth-code-flow.d.ts.map +1 -1
- package/build/ts/server/authenticate/admin/strategies/auth-code-flow.js +27 -7
- package/build/ts/server/authenticate/admin/strategies/auth-code-flow.js.map +1 -1
- package/build/ts/server/authenticate/admin/strategies/token-exchange.d.ts +17 -0
- package/build/ts/server/authenticate/admin/strategies/token-exchange.d.ts.map +1 -0
- package/build/ts/server/authenticate/admin/strategies/token-exchange.js +163 -0
- package/build/ts/server/authenticate/admin/strategies/token-exchange.js.map +1 -0
- package/build/ts/server/authenticate/admin/strategies/types.d.ts +16 -5
- package/build/ts/server/authenticate/admin/strategies/types.d.ts.map +1 -1
- package/build/ts/server/authenticate/admin/types.d.ts +0 -4
- package/build/ts/server/authenticate/admin/types.d.ts.map +1 -1
- package/build/ts/server/authenticate/const.d.ts +3 -0
- package/build/ts/server/authenticate/const.d.ts.map +1 -1
- package/build/ts/server/authenticate/const.js +4 -1
- package/build/ts/server/authenticate/const.js.map +1 -1
- package/build/ts/server/authenticate/helpers/add-response-headers.js.map +1 -1
- package/build/ts/server/authenticate/helpers/ensure-cors-headers.js.map +1 -1
- package/build/ts/server/authenticate/helpers/idempotent-promise-handler.d.ts +12 -0
- package/build/ts/server/authenticate/helpers/idempotent-promise-handler.d.ts.map +1 -0
- package/build/ts/server/authenticate/helpers/idempotent-promise-handler.js +53 -0
- package/build/ts/server/authenticate/helpers/idempotent-promise-handler.js.map +1 -0
- package/build/ts/server/authenticate/helpers/index.d.ts +1 -0
- package/build/ts/server/authenticate/helpers/index.d.ts.map +1 -1
- package/build/ts/server/authenticate/helpers/index.js +1 -0
- package/build/ts/server/authenticate/helpers/index.js.map +1 -1
- package/build/ts/server/authenticate/helpers/reject-bot-request.js.map +1 -1
- package/build/ts/server/authenticate/helpers/respond-to-invalid-session-token.d.ts +9 -0
- package/build/ts/server/authenticate/helpers/respond-to-invalid-session-token.d.ts.map +1 -0
- package/build/ts/server/authenticate/helpers/respond-to-invalid-session-token.js +20 -0
- package/build/ts/server/authenticate/helpers/respond-to-invalid-session-token.js.map +1 -0
- package/build/ts/server/authenticate/helpers/respond-to-options-request.js.map +1 -1
- package/build/ts/server/authenticate/login/login.d.ts.map +1 -1
- package/build/ts/server/authenticate/login/login.js +6 -2
- package/build/ts/server/authenticate/login/login.js.map +1 -1
- package/build/ts/server/authenticate/public/appProxy/authenticate.js.map +1 -1
- package/build/ts/server/authenticate/public/checkout/authenticate.js.map +1 -1
- package/build/ts/server/authenticate/public/factory.js.map +1 -1
- package/build/ts/server/authenticate/webhooks/authenticate.js.map +1 -1
- package/build/ts/server/authenticate/webhooks/register.d.ts +1 -1
- package/build/ts/server/authenticate/webhooks/register.d.ts.map +1 -1
- package/build/ts/server/authenticate/webhooks/register.js +20 -1
- package/build/ts/server/authenticate/webhooks/register.js.map +1 -1
- package/build/ts/server/authenticate/webhooks/types.d.ts +12 -5
- package/build/ts/server/authenticate/webhooks/types.d.ts.map +1 -1
- package/build/ts/server/boundary/error.js.map +1 -1
- package/build/ts/server/boundary/headers.js.map +1 -1
- package/build/ts/server/clients/admin/graphql.d.ts +3 -3
- package/build/ts/server/clients/admin/graphql.d.ts.map +1 -1
- package/build/ts/server/clients/admin/graphql.js +5 -8
- package/build/ts/server/clients/admin/graphql.js.map +1 -1
- package/build/ts/server/clients/admin/rest.js.map +1 -1
- package/build/ts/server/clients/admin/types.d.ts +2 -1
- package/build/ts/server/clients/admin/types.d.ts.map +1 -1
- package/build/ts/server/clients/storefront/factory.d.ts.map +1 -1
- package/build/ts/server/clients/storefront/factory.js +5 -8
- package/build/ts/server/clients/storefront/factory.js.map +1 -1
- package/build/ts/server/clients/storefront/types.d.ts +2 -1
- package/build/ts/server/clients/storefront/types.d.ts.map +1 -1
- package/build/ts/server/clients/types.d.ts +4 -7
- package/build/ts/server/clients/types.d.ts.map +1 -1
- package/build/ts/server/config-types.d.ts +2 -0
- package/build/ts/server/config-types.d.ts.map +1 -1
- package/build/ts/server/future/flags.d.ts +6 -0
- package/build/ts/server/future/flags.d.ts.map +1 -1
- package/build/ts/server/override-logger.js.map +1 -1
- package/build/ts/server/shopify-app.d.ts +1 -0
- package/build/ts/server/shopify-app.d.ts.map +1 -1
- package/build/ts/server/shopify-app.js +11 -5
- package/build/ts/server/shopify-app.js.map +1 -1
- package/build/ts/server/types.d.ts +10 -4
- package/build/ts/server/types.d.ts.map +1 -1
- package/build/ts/server/types.js +2 -2
- package/build/ts/server/types.js.map +1 -1
- package/build/ts/server/unauthenticated/admin/factory.js.map +1 -1
- package/build/ts/server/unauthenticated/storefront/factory.js.map +1 -1
- package/build/ts/server/version.d.ts +1 -1
- package/build/ts/server/version.js +1 -1
- package/package.json +14 -16
|
@@ -4,6 +4,7 @@ var crypto = require('crypto');
|
|
|
4
4
|
var runtime = require('@shopify/shopify-api/runtime');
|
|
5
5
|
var appBridgeUrl = require('../../authenticate/helpers/app-bridge-url.js');
|
|
6
6
|
require('isbot');
|
|
7
|
+
require('@remix-run/server-runtime');
|
|
7
8
|
|
|
8
9
|
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
|
|
9
10
|
|
|
@@ -7,6 +7,7 @@ var validateSessionToken = require('../helpers/validate-session-token.js');
|
|
|
7
7
|
var getSessionTokenHeader = require('../helpers/get-session-token-header.js');
|
|
8
8
|
var rejectBotRequest = require('../helpers/reject-bot-request.js');
|
|
9
9
|
var respondToOptionsRequest = require('../helpers/respond-to-options-request.js');
|
|
10
|
+
require('@remix-run/server-runtime');
|
|
10
11
|
var cancel = require('./billing/cancel.js');
|
|
11
12
|
var require$1 = require('./billing/require.js');
|
|
12
13
|
var request = require('./billing/request.js');
|
|
@@ -14,7 +15,6 @@ var createAdminApiContext = require('./helpers/create-admin-api-context.js');
|
|
|
14
15
|
var ensureAppIsEmbeddedIfRequired = require('./helpers/ensure-app-is-embedded-if-required.js');
|
|
15
16
|
var ensureSessionTokenSearchParamIfRequired = require('./helpers/ensure-session-token-search-param-if-required.js');
|
|
16
17
|
require('@shopify/shopify-api');
|
|
17
|
-
require('@remix-run/server-runtime');
|
|
18
18
|
var redirect = require('./helpers/redirect.js');
|
|
19
19
|
var renderAppBridge = require('./helpers/render-app-bridge.js');
|
|
20
20
|
var validateShopAndHostParams = require('./helpers/validate-shop-and-host-params.js');
|
|
@@ -55,13 +55,9 @@ function authStrategyFactory({
|
|
|
55
55
|
});
|
|
56
56
|
}
|
|
57
57
|
}
|
|
58
|
-
function createContext(request$1, session, sessionToken) {
|
|
58
|
+
function createContext(request$1, session, authStrategy, sessionToken) {
|
|
59
59
|
const context = {
|
|
60
|
-
admin: createAdminApiContext.createAdminApiContext(request$1,
|
|
61
|
-
api,
|
|
62
|
-
logger,
|
|
63
|
-
config
|
|
64
|
-
}),
|
|
60
|
+
admin: createAdminApiContext.createAdminApiContext(session, params, authStrategy.handleClientError(request$1)),
|
|
65
61
|
billing: {
|
|
66
62
|
require: require$1.requireBillingFactory(params, request$1, session),
|
|
67
63
|
request: request.requestBillingFactory(params, request$1, session),
|
|
@@ -99,18 +95,23 @@ function authStrategyFactory({
|
|
|
99
95
|
const {
|
|
100
96
|
payload,
|
|
101
97
|
shop,
|
|
102
|
-
sessionId
|
|
98
|
+
sessionId,
|
|
99
|
+
sessionToken
|
|
103
100
|
} = await getSessionTokenContext(params, request);
|
|
104
101
|
logger.debug('Loading session from storage', {
|
|
105
102
|
sessionId
|
|
106
103
|
});
|
|
107
104
|
const existingSession = sessionId ? await config.sessionStorage.loadSession(sessionId) : undefined;
|
|
108
|
-
const session = await strategy.authenticate(request,
|
|
105
|
+
const session = await strategy.authenticate(request, {
|
|
106
|
+
session: existingSession,
|
|
107
|
+
sessionToken,
|
|
108
|
+
shop
|
|
109
|
+
});
|
|
109
110
|
logger.debug('Request is valid, loaded session from session token', {
|
|
110
111
|
shop: session.shop,
|
|
111
112
|
isOnline: session.isOnline
|
|
112
113
|
});
|
|
113
|
-
return createContext(request, session, payload);
|
|
114
|
+
return createContext(request, session, strategy, payload);
|
|
114
115
|
} catch (errorOrResponse) {
|
|
115
116
|
if (errorOrResponse instanceof Response) {
|
|
116
117
|
ensureCorsHeaders.ensureCORSHeadersFactory(params, request)(errorOrResponse);
|
|
@@ -129,10 +130,10 @@ async function getSessionTokenContext(params, request) {
|
|
|
129
130
|
const searchParamSessionToken = getSessionTokenHeader.getSessionTokenFromUrlParam(request);
|
|
130
131
|
const sessionToken = headerSessionToken || searchParamSessionToken;
|
|
131
132
|
logger.debug('Attempting to authenticate session token', {
|
|
132
|
-
sessionToken: {
|
|
133
|
+
sessionToken: JSON.stringify({
|
|
133
134
|
header: headerSessionToken,
|
|
134
135
|
search: searchParamSessionToken
|
|
135
|
-
}
|
|
136
|
+
})
|
|
136
137
|
});
|
|
137
138
|
if (config.isEmbeddedApp) {
|
|
138
139
|
const payload = await validateSessionToken.validateSessionToken({
|
|
@@ -150,7 +151,8 @@ async function getSessionTokenContext(params, request) {
|
|
|
150
151
|
return {
|
|
151
152
|
shop,
|
|
152
153
|
payload,
|
|
153
|
-
sessionId
|
|
154
|
+
sessionId,
|
|
155
|
+
sessionToken
|
|
154
156
|
};
|
|
155
157
|
}
|
|
156
158
|
const url = new URL(request.url);
|
|
@@ -162,7 +164,8 @@ async function getSessionTokenContext(params, request) {
|
|
|
162
164
|
return {
|
|
163
165
|
shop,
|
|
164
166
|
sessionId,
|
|
165
|
-
payload: undefined
|
|
167
|
+
payload: undefined,
|
|
168
|
+
sessionToken
|
|
166
169
|
};
|
|
167
170
|
}
|
|
168
171
|
|
|
@@ -3,9 +3,8 @@
|
|
|
3
3
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
|
5
5
|
var shopifyApi = require('@shopify/shopify-api');
|
|
6
|
-
require('@shopify/shopify-api/runtime');
|
|
7
|
-
var redirectToAuthPage = require('../helpers/redirect-to-auth-page.js');
|
|
8
6
|
require('@remix-run/server-runtime');
|
|
7
|
+
var redirectToAuthPage = require('../helpers/redirect-to-auth-page.js');
|
|
9
8
|
|
|
10
9
|
function cancelBillingFactory(params, request, session) {
|
|
11
10
|
return async function cancelBilling(options) {
|
|
@@ -4,7 +4,6 @@ Object.defineProperty(exports, '__esModule', { value: true });
|
|
|
4
4
|
|
|
5
5
|
var shopifyApi = require('@shopify/shopify-api');
|
|
6
6
|
var serverRuntime = require('@remix-run/server-runtime');
|
|
7
|
-
require('@shopify/shopify-api/runtime');
|
|
8
7
|
var redirectToAuthPage = require('../helpers/redirect-to-auth-page.js');
|
|
9
8
|
var redirectWithAppBridgeHeaders = require('../helpers/redirect-with-app-bridge-headers.js');
|
|
10
9
|
|
|
@@ -3,9 +3,8 @@
|
|
|
3
3
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
|
5
5
|
var shopifyApi = require('@shopify/shopify-api');
|
|
6
|
-
require('@shopify/shopify-api/runtime');
|
|
7
|
-
var redirectToAuthPage = require('../helpers/redirect-to-auth-page.js');
|
|
8
6
|
require('@remix-run/server-runtime');
|
|
7
|
+
var redirectToAuthPage = require('../helpers/redirect-to-auth-page.js');
|
|
9
8
|
|
|
10
9
|
function requireBillingFactory(params, request, session) {
|
|
11
10
|
const {
|
|
@@ -3,15 +3,12 @@
|
|
|
3
3
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
|
5
5
|
var factory = require('../../../clients/admin/factory.js');
|
|
6
|
-
var handleClientError = require('./handle-client-error.js');
|
|
7
6
|
|
|
8
|
-
function createAdminApiContext(
|
|
7
|
+
function createAdminApiContext(session, params, handleClientError) {
|
|
9
8
|
return factory.adminClientFactory({
|
|
10
9
|
session,
|
|
11
10
|
params,
|
|
12
|
-
handleClientError
|
|
13
|
-
request
|
|
14
|
-
})
|
|
11
|
+
handleClientError
|
|
15
12
|
});
|
|
16
13
|
}
|
|
17
14
|
|
|
@@ -3,10 +3,10 @@
|
|
|
3
3
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
|
5
5
|
var shopifyApi = require('@shopify/shopify-api');
|
|
6
|
-
var redirectToAuthPage = require('./redirect-to-auth-page.js');
|
|
7
6
|
|
|
8
7
|
function handleClientErrorFactory({
|
|
9
|
-
request
|
|
8
|
+
request,
|
|
9
|
+
onError
|
|
10
10
|
}) {
|
|
11
11
|
return async function handleClientError({
|
|
12
12
|
error,
|
|
@@ -22,8 +22,12 @@ function handleClientErrorFactory({
|
|
|
22
22
|
statusText: error.response.statusText,
|
|
23
23
|
body: JSON.stringify(error.response.body)
|
|
24
24
|
});
|
|
25
|
-
if (
|
|
26
|
-
|
|
25
|
+
if (onError) {
|
|
26
|
+
await onError({
|
|
27
|
+
request,
|
|
28
|
+
session,
|
|
29
|
+
error
|
|
30
|
+
});
|
|
27
31
|
}
|
|
28
32
|
|
|
29
33
|
// forward a minimal copy of the upstream HTTP response instead of an Error:
|
|
@@ -11,12 +11,14 @@ const redirectToBouncePage = (params, url) => {
|
|
|
11
11
|
|
|
12
12
|
// Make sure we always point to the configured app URL so it also works behind reverse proxies (that alter the Host
|
|
13
13
|
// header).
|
|
14
|
-
|
|
14
|
+
const searchParams = url.searchParams;
|
|
15
|
+
searchParams.delete('id_token');
|
|
16
|
+
searchParams.set('shopify-reload', `${config.appUrl}${url.pathname}?${searchParams.toString()}`);
|
|
15
17
|
|
|
16
18
|
// eslint-disable-next-line no-warning-comments
|
|
17
19
|
// TODO Make sure this works on chrome without a tunnel (weird HTTPS redirect issue)
|
|
18
20
|
// https://github.com/orgs/Shopify/projects/6899/views/1?pane=issue&itemId=28376650
|
|
19
|
-
throw serverRuntime.redirect(`${config.auth.patchSessionTokenPath}
|
|
21
|
+
throw serverRuntime.redirect(`${config.auth.patchSessionTokenPath}?${searchParams.toString()}`);
|
|
20
22
|
};
|
|
21
23
|
|
|
22
24
|
exports.redirectToBouncePage = redirectToBouncePage;
|
|
@@ -49,13 +49,9 @@ function isBounceRequest(request) {
|
|
|
49
49
|
return Boolean(getSessionTokenHeader.getSessionTokenHeader(request)) && request.headers.has('X-Shopify-Bounce');
|
|
50
50
|
}
|
|
51
51
|
function isDataRequest(request) {
|
|
52
|
-
const {
|
|
53
|
-
searchParams
|
|
54
|
-
} = new URL(request.url);
|
|
55
52
|
const isGet = request.method === 'GET';
|
|
56
53
|
const sessionTokenHeader = Boolean(getSessionTokenHeader.getSessionTokenHeader(request));
|
|
57
|
-
|
|
58
|
-
return sessionTokenHeader && !sessionTokenSearchParam && !isBounceRequest(request) && (!isEmbeddedRequest(request) || !isGet);
|
|
54
|
+
return sessionTokenHeader && !isBounceRequest(request) && (!isEmbeddedRequest(request) || !isGet);
|
|
59
55
|
}
|
|
60
56
|
function isEmbeddedRequest(request) {
|
|
61
57
|
const {
|
|
@@ -4,7 +4,7 @@ Object.defineProperty(exports, '__esModule', { value: true });
|
|
|
4
4
|
|
|
5
5
|
var createAdminApiContext = require('./create-admin-api-context.js');
|
|
6
6
|
|
|
7
|
-
async function triggerAfterAuthHook(params, session, request) {
|
|
7
|
+
async function triggerAfterAuthHook(params, session, request, authStrategy) {
|
|
8
8
|
const {
|
|
9
9
|
config,
|
|
10
10
|
logger
|
|
@@ -13,7 +13,7 @@ async function triggerAfterAuthHook(params, session, request) {
|
|
|
13
13
|
logger.info('Running afterAuth hook');
|
|
14
14
|
await config.hooks.afterAuth({
|
|
15
15
|
session,
|
|
16
|
-
admin: createAdminApiContext.createAdminApiContext(
|
|
16
|
+
admin: createAdminApiContext.createAdminApiContext(session, params, authStrategy.handleClientError(request))
|
|
17
17
|
});
|
|
18
18
|
}
|
|
19
19
|
}
|
|
@@ -4,10 +4,10 @@ Object.defineProperty(exports, '__esModule', { value: true });
|
|
|
4
4
|
|
|
5
5
|
var shopifyApi = require('@shopify/shopify-api');
|
|
6
6
|
var beginAuth = require('../helpers/begin-auth.js');
|
|
7
|
-
require('@shopify/shopify-api/runtime');
|
|
8
|
-
var redirectToAuthPage = require('../helpers/redirect-to-auth-page.js');
|
|
9
7
|
var redirectToShopifyOrAppRoot = require('../helpers/redirect-to-shopify-or-app-root.js');
|
|
10
8
|
require('@remix-run/server-runtime');
|
|
9
|
+
var handleClientError = require('../helpers/handle-client-error.js');
|
|
10
|
+
var redirectToAuthPage = require('../helpers/redirect-to-auth-page.js');
|
|
11
11
|
var redirectWithExitiframe = require('../helpers/redirect-with-exitiframe.js');
|
|
12
12
|
var getSessionTokenHeader = require('../../helpers/get-session-token-header.js');
|
|
13
13
|
var triggerAfterAuthHook = require('../helpers/trigger-after-auth-hook.js');
|
|
@@ -53,12 +53,16 @@ class AuthCodeFlowStrategy {
|
|
|
53
53
|
await this.ensureInstalledOnShop(request);
|
|
54
54
|
}
|
|
55
55
|
}
|
|
56
|
-
async authenticate(request,
|
|
56
|
+
async authenticate(request, sessionContext) {
|
|
57
57
|
const {
|
|
58
58
|
api,
|
|
59
59
|
config,
|
|
60
60
|
logger
|
|
61
61
|
} = this;
|
|
62
|
+
const {
|
|
63
|
+
shop,
|
|
64
|
+
session
|
|
65
|
+
} = sessionContext;
|
|
62
66
|
if (!session) {
|
|
63
67
|
logger.debug('No session found, redirecting to OAuth', {
|
|
64
68
|
shop
|
|
@@ -83,6 +87,28 @@ class AuthCodeFlowStrategy {
|
|
|
83
87
|
});
|
|
84
88
|
return session;
|
|
85
89
|
}
|
|
90
|
+
handleClientError(request) {
|
|
91
|
+
const {
|
|
92
|
+
api,
|
|
93
|
+
config,
|
|
94
|
+
logger
|
|
95
|
+
} = this;
|
|
96
|
+
return handleClientError.handleClientErrorFactory({
|
|
97
|
+
request,
|
|
98
|
+
onError: async ({
|
|
99
|
+
session,
|
|
100
|
+
error
|
|
101
|
+
}) => {
|
|
102
|
+
if (error.response.code === 401) {
|
|
103
|
+
throw await redirectToAuthPage.redirectToAuthPage({
|
|
104
|
+
api,
|
|
105
|
+
config,
|
|
106
|
+
logger
|
|
107
|
+
}, request, session.shop);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
}
|
|
86
112
|
async ensureInstalledOnShop(request) {
|
|
87
113
|
const {
|
|
88
114
|
api,
|
|
@@ -198,7 +224,7 @@ class AuthCodeFlowStrategy {
|
|
|
198
224
|
api,
|
|
199
225
|
config,
|
|
200
226
|
logger
|
|
201
|
-
}, session, request);
|
|
227
|
+
}, session, request, this);
|
|
202
228
|
throw await redirectToShopifyOrAppRoot.redirectToShopifyOrAppRoot(request, {
|
|
203
229
|
api,
|
|
204
230
|
config,
|
|
@@ -234,15 +260,13 @@ class AuthCodeFlowStrategy {
|
|
|
234
260
|
const client = new api.clients.Graphql({
|
|
235
261
|
session
|
|
236
262
|
});
|
|
237
|
-
await client.
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
name
|
|
242
|
-
}
|
|
263
|
+
await client.request(`#graphql
|
|
264
|
+
query shopifyAppShopName {
|
|
265
|
+
shop {
|
|
266
|
+
name
|
|
243
267
|
}
|
|
244
|
-
|
|
245
|
-
|
|
268
|
+
}
|
|
269
|
+
`);
|
|
246
270
|
}
|
|
247
271
|
async oauthCallbackError(error, request, shop) {
|
|
248
272
|
const {
|
|
@@ -296,7 +320,7 @@ class AuthCodeFlowStrategy {
|
|
|
296
320
|
shop
|
|
297
321
|
};
|
|
298
322
|
if (error.response) {
|
|
299
|
-
context.response = JSON.stringify(error.
|
|
323
|
+
context.response = JSON.stringify(error.body);
|
|
300
324
|
}
|
|
301
325
|
logger.error(`Unexpected error during session validation: ${error.message}`, context);
|
|
302
326
|
throw new Response(undefined, {
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
5
|
+
var shopifyApi = require('@shopify/shopify-api');
|
|
6
|
+
require('isbot');
|
|
7
|
+
var respondToInvalidSessionToken = require('../../helpers/respond-to-invalid-session-token.js');
|
|
8
|
+
require('@remix-run/server-runtime');
|
|
9
|
+
var handleClientError = require('../helpers/handle-client-error.js');
|
|
10
|
+
var triggerAfterAuthHook = require('../helpers/trigger-after-auth-hook.js');
|
|
11
|
+
|
|
12
|
+
class TokenExchangeStrategy {
|
|
13
|
+
constructor({
|
|
14
|
+
api,
|
|
15
|
+
config,
|
|
16
|
+
logger
|
|
17
|
+
}) {
|
|
18
|
+
this.api = void 0;
|
|
19
|
+
this.config = void 0;
|
|
20
|
+
this.logger = void 0;
|
|
21
|
+
this.api = api;
|
|
22
|
+
this.config = config;
|
|
23
|
+
this.logger = logger;
|
|
24
|
+
}
|
|
25
|
+
async respondToOAuthRequests(_request) {}
|
|
26
|
+
async authenticate(request, sessionContext) {
|
|
27
|
+
const {
|
|
28
|
+
api,
|
|
29
|
+
config,
|
|
30
|
+
logger
|
|
31
|
+
} = this;
|
|
32
|
+
const {
|
|
33
|
+
shop,
|
|
34
|
+
session,
|
|
35
|
+
sessionToken
|
|
36
|
+
} = sessionContext;
|
|
37
|
+
if (!sessionToken) throw new shopifyApi.InvalidJwtError();
|
|
38
|
+
if (!session || session.isExpired()) {
|
|
39
|
+
logger.info('No valid session found');
|
|
40
|
+
logger.info('Requesting offline access token');
|
|
41
|
+
const {
|
|
42
|
+
session: offlineSession
|
|
43
|
+
} = await this.exchangeToken({
|
|
44
|
+
request,
|
|
45
|
+
sessionToken,
|
|
46
|
+
shop,
|
|
47
|
+
requestedTokenType: shopifyApi.RequestedTokenType.OfflineAccessToken
|
|
48
|
+
});
|
|
49
|
+
await config.sessionStorage.storeSession(offlineSession);
|
|
50
|
+
let newSession = offlineSession;
|
|
51
|
+
if (config.useOnlineTokens) {
|
|
52
|
+
logger.info('Requesting online access token');
|
|
53
|
+
const {
|
|
54
|
+
session: onlineSession
|
|
55
|
+
} = await this.exchangeToken({
|
|
56
|
+
request,
|
|
57
|
+
sessionToken,
|
|
58
|
+
shop,
|
|
59
|
+
requestedTokenType: shopifyApi.RequestedTokenType.OnlineAccessToken
|
|
60
|
+
});
|
|
61
|
+
await config.sessionStorage.storeSession(onlineSession);
|
|
62
|
+
newSession = onlineSession;
|
|
63
|
+
}
|
|
64
|
+
try {
|
|
65
|
+
await this.handleAfterAuthHook({
|
|
66
|
+
api,
|
|
67
|
+
config,
|
|
68
|
+
logger
|
|
69
|
+
}, newSession, request, sessionToken);
|
|
70
|
+
} catch (error) {
|
|
71
|
+
throw new Response(undefined, {
|
|
72
|
+
status: 500,
|
|
73
|
+
statusText: 'Internal Server Error'
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
return newSession;
|
|
77
|
+
}
|
|
78
|
+
return session;
|
|
79
|
+
}
|
|
80
|
+
handleClientError(request) {
|
|
81
|
+
const {
|
|
82
|
+
api,
|
|
83
|
+
config,
|
|
84
|
+
logger
|
|
85
|
+
} = this;
|
|
86
|
+
return handleClientError.handleClientErrorFactory({
|
|
87
|
+
request,
|
|
88
|
+
onError: async ({
|
|
89
|
+
session,
|
|
90
|
+
error
|
|
91
|
+
}) => {
|
|
92
|
+
if (error.response.code === 401) {
|
|
93
|
+
config.sessionStorage.deleteSession(session.id);
|
|
94
|
+
respondToInvalidSessionToken.respondToInvalidSessionToken({
|
|
95
|
+
params: {
|
|
96
|
+
config,
|
|
97
|
+
api,
|
|
98
|
+
logger
|
|
99
|
+
},
|
|
100
|
+
request
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
async exchangeToken({
|
|
107
|
+
request,
|
|
108
|
+
shop,
|
|
109
|
+
sessionToken,
|
|
110
|
+
requestedTokenType
|
|
111
|
+
}) {
|
|
112
|
+
const {
|
|
113
|
+
api,
|
|
114
|
+
config,
|
|
115
|
+
logger
|
|
116
|
+
} = this;
|
|
117
|
+
try {
|
|
118
|
+
return await api.auth.tokenExchange({
|
|
119
|
+
sessionToken,
|
|
120
|
+
shop,
|
|
121
|
+
requestedTokenType
|
|
122
|
+
});
|
|
123
|
+
} catch (error) {
|
|
124
|
+
var _error$response$body;
|
|
125
|
+
if (error instanceof shopifyApi.InvalidJwtError || error instanceof shopifyApi.HttpResponseError && error.response.code === 400 && ((_error$response$body = error.response.body) === null || _error$response$body === void 0 ? void 0 : _error$response$body.error) === 'invalid_subject_token') {
|
|
126
|
+
throw respondToInvalidSessionToken.respondToInvalidSessionToken({
|
|
127
|
+
params: {
|
|
128
|
+
api,
|
|
129
|
+
config,
|
|
130
|
+
logger
|
|
131
|
+
},
|
|
132
|
+
request,
|
|
133
|
+
retryRequest: true
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
throw new Response(undefined, {
|
|
137
|
+
status: 500,
|
|
138
|
+
statusText: 'Internal Server Error'
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
async handleAfterAuthHook(params, session, request, sessionToken) {
|
|
143
|
+
const {
|
|
144
|
+
config
|
|
145
|
+
} = params;
|
|
146
|
+
await config.idempotentPromiseHandler.handlePromise({
|
|
147
|
+
promiseFunction: () => {
|
|
148
|
+
return triggerAfterAuthHook.triggerAfterAuthHook(params, session, request, this);
|
|
149
|
+
},
|
|
150
|
+
identifier: sessionToken
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
exports.TokenExchangeStrategy = TokenExchangeStrategy;
|
|
@@ -4,6 +4,10 @@ Object.defineProperty(exports, '__esModule', { value: true });
|
|
|
4
4
|
|
|
5
5
|
const APP_BRIDGE_URL = 'https://cdn.shopify.com/shopifycloud/app-bridge.js';
|
|
6
6
|
const REAUTH_URL_HEADER = 'X-Shopify-API-Request-Failure-Reauthorize-Url';
|
|
7
|
+
const RETRY_INVALID_SESSION_HEADER = {
|
|
8
|
+
'X-Shopify-Retry-Invalid-Session-Request': '1'
|
|
9
|
+
};
|
|
7
10
|
|
|
8
11
|
exports.APP_BRIDGE_URL = APP_BRIDGE_URL;
|
|
9
12
|
exports.REAUTH_URL_HEADER = REAUTH_URL_HEADER;
|
|
13
|
+
exports.RETRY_INVALID_SESSION_HEADER = RETRY_INVALID_SESSION_HEADER;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
5
|
+
const IDENTIFIER_TTL_MS = 60000;
|
|
6
|
+
class IdempotentPromiseHandler {
|
|
7
|
+
constructor() {
|
|
8
|
+
this.identifiers = void 0;
|
|
9
|
+
this.identifiers = new Map();
|
|
10
|
+
}
|
|
11
|
+
async handlePromise({
|
|
12
|
+
promiseFunction,
|
|
13
|
+
identifier
|
|
14
|
+
}) {
|
|
15
|
+
try {
|
|
16
|
+
if (this.isPromiseRunnable(identifier)) {
|
|
17
|
+
await promiseFunction();
|
|
18
|
+
}
|
|
19
|
+
} finally {
|
|
20
|
+
this.clearStaleIdentifiers();
|
|
21
|
+
}
|
|
22
|
+
return Promise.resolve();
|
|
23
|
+
}
|
|
24
|
+
isPromiseRunnable(identifier) {
|
|
25
|
+
if (!this.identifiers.has(identifier)) {
|
|
26
|
+
this.identifiers.set(identifier, Date.now());
|
|
27
|
+
return true;
|
|
28
|
+
}
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
31
|
+
async clearStaleIdentifiers() {
|
|
32
|
+
this.identifiers.forEach((date, identifier, map) => {
|
|
33
|
+
if (Date.now() - date > IDENTIFIER_TTL_MS) {
|
|
34
|
+
map.delete(identifier);
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
exports.IdempotentPromiseHandler = IdempotentPromiseHandler;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
5
|
+
var redirectToBouncePage = require('../admin/helpers/redirect-to-bounce-page.js');
|
|
6
|
+
var _const = require('../const.js');
|
|
7
|
+
|
|
8
|
+
function respondToInvalidSessionToken({
|
|
9
|
+
params,
|
|
10
|
+
request,
|
|
11
|
+
retryRequest = false
|
|
12
|
+
}) {
|
|
13
|
+
const {
|
|
14
|
+
api,
|
|
15
|
+
logger,
|
|
16
|
+
config
|
|
17
|
+
} = params;
|
|
18
|
+
const isDocumentRequest = !request.headers.get('authorization');
|
|
19
|
+
if (isDocumentRequest) {
|
|
20
|
+
return redirectToBouncePage.redirectToBouncePage({
|
|
21
|
+
api,
|
|
22
|
+
logger,
|
|
23
|
+
config
|
|
24
|
+
}, new URL(request.url));
|
|
25
|
+
}
|
|
26
|
+
throw new Response(undefined, {
|
|
27
|
+
status: 401,
|
|
28
|
+
statusText: 'Unauthorized',
|
|
29
|
+
headers: retryRequest ? _const.RETRY_INVALID_SESSION_HEADER : {}
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
exports.respondToInvalidSessionToken = respondToInvalidSessionToken;
|
|
@@ -37,7 +37,11 @@ function loginFactory(params) {
|
|
|
37
37
|
shop: types.LoginErrorType.InvalidShop
|
|
38
38
|
};
|
|
39
39
|
}
|
|
40
|
-
const
|
|
40
|
+
const authPath = `${config.appUrl}${config.auth.path}?shop=${sanitizedShop}`;
|
|
41
|
+
const adminPath = api.utils.legacyUrlToShopAdminUrl(sanitizedShop);
|
|
42
|
+
const installPath = `https://${adminPath}/oauth/install?client_id=${config.apiKey}`;
|
|
43
|
+
const shouldInstall = config.isEmbeddedApp && config.future.unstable_newEmbeddedAuthStrategy;
|
|
44
|
+
const redirectUrl = shouldInstall ? installPath : authPath;
|
|
41
45
|
logger.info(`Redirecting login request to ${redirectUrl}`, {
|
|
42
46
|
shop: sanitizedShop
|
|
43
47
|
});
|
|
@@ -7,6 +7,7 @@ var validateSessionToken = require('../../helpers/validate-session-token.js');
|
|
|
7
7
|
var getSessionTokenHeader = require('../../helpers/get-session-token-header.js');
|
|
8
8
|
var rejectBotRequest = require('../../helpers/reject-bot-request.js');
|
|
9
9
|
var respondToOptionsRequest = require('../../helpers/respond-to-options-request.js');
|
|
10
|
+
require('@remix-run/server-runtime');
|
|
10
11
|
|
|
11
12
|
function authenticateCheckoutFactory(params) {
|
|
12
13
|
return async function authenticateCheckout(request, options = {}) {
|
|
@@ -4,9 +4,8 @@ Object.defineProperty(exports, '__esModule', { value: true });
|
|
|
4
4
|
|
|
5
5
|
var shopifyApi = require('@shopify/shopify-api');
|
|
6
6
|
var factory = require('../../clients/admin/factory.js');
|
|
7
|
-
require('@shopify/shopify-api/runtime');
|
|
8
|
-
var handleClientError = require('../admin/helpers/handle-client-error.js');
|
|
9
7
|
require('@remix-run/server-runtime');
|
|
8
|
+
var handleClientError = require('../admin/helpers/handle-client-error.js');
|
|
10
9
|
|
|
11
10
|
function authenticateWebhookFactory(params) {
|
|
12
11
|
const {
|
|
@@ -33,6 +33,22 @@ function registerWebhooksFactory({
|
|
|
33
33
|
});
|
|
34
34
|
});
|
|
35
35
|
return response;
|
|
36
|
+
}).catch(error => {
|
|
37
|
+
var _error$body, _error$body$errors;
|
|
38
|
+
const graphQLErrors = ((_error$body = error.body) === null || _error$body === void 0 ? void 0 : (_error$body$errors = _error$body.errors) === null || _error$body$errors === void 0 ? void 0 : _error$body$errors.graphQLErrors) || [];
|
|
39
|
+
const throttled = graphQLErrors.find(({
|
|
40
|
+
extensions: {
|
|
41
|
+
code
|
|
42
|
+
}
|
|
43
|
+
}) => code === 'THROTTLED');
|
|
44
|
+
if (throttled) {
|
|
45
|
+
logger.error('Failed to register webhooks', {
|
|
46
|
+
shop: session.shop,
|
|
47
|
+
error: JSON.stringify(error)
|
|
48
|
+
});
|
|
49
|
+
} else {
|
|
50
|
+
throw error;
|
|
51
|
+
}
|
|
36
52
|
});
|
|
37
53
|
};
|
|
38
54
|
}
|
|
@@ -2,8 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
|
5
|
-
var runtime = require('@shopify/shopify-api/runtime');
|
|
6
|
-
|
|
7
5
|
// eslint-disable-next-line no-warning-comments
|
|
8
6
|
// TODO: This is actually just a call through to the Shopify API client, but with a different API. We should eventually
|
|
9
7
|
// move this over to the library layer. While doing that, we should also allow the apiVersion to be passed into the REST
|
|
@@ -20,17 +18,12 @@ function graphqlClientFactory({
|
|
|
20
18
|
});
|
|
21
19
|
try {
|
|
22
20
|
// We convert the incoming response to a Response object to bring this client closer to the Remix client.
|
|
23
|
-
const apiResponse = await client.
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
},
|
|
28
|
-
tries: options === null || options === void 0 ? void 0 : options.tries,
|
|
29
|
-
extraHeaders: options === null || options === void 0 ? void 0 : options.headers
|
|
30
|
-
});
|
|
31
|
-
return new Response(JSON.stringify(apiResponse.body), {
|
|
32
|
-
headers: runtime.flatHeaders(apiResponse.headers)
|
|
21
|
+
const apiResponse = await client.request(operation, {
|
|
22
|
+
variables: options === null || options === void 0 ? void 0 : options.variables,
|
|
23
|
+
retries: options !== null && options !== void 0 && options.tries ? options.tries - 1 : 0,
|
|
24
|
+
headers: options === null || options === void 0 ? void 0 : options.headers
|
|
33
25
|
});
|
|
26
|
+
return new Response(JSON.stringify(apiResponse));
|
|
34
27
|
} catch (error) {
|
|
35
28
|
if (handleClientError) {
|
|
36
29
|
throw await handleClientError({
|