@shopify/shopify-app-remix 2.0.2 → 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/build/cjs/server/authenticate/admin/authenticate.js +119 -501
- package/build/cjs/server/authenticate/admin/billing/cancel.js +1 -0
- package/build/cjs/server/authenticate/admin/billing/request.js +1 -0
- package/build/cjs/server/authenticate/admin/billing/require.js +1 -0
- package/build/cjs/server/authenticate/admin/helpers/create-admin-api-context.js +18 -0
- package/build/cjs/server/authenticate/admin/helpers/ensure-app-is-embedded-if-required.js +27 -0
- package/build/cjs/server/authenticate/admin/helpers/ensure-session-token-search-param-if-required.js +25 -0
- package/build/cjs/server/authenticate/admin/helpers/redirect-to-bounce-page.js +22 -0
- package/build/cjs/server/authenticate/admin/helpers/redirect-to-shopify-or-app-root.js +22 -0
- package/build/cjs/server/authenticate/admin/helpers/trigger-after-auth-hook.js +21 -0
- package/build/cjs/server/authenticate/admin/helpers/validate-shop-and-host-params.js +32 -0
- package/build/cjs/server/authenticate/admin/strategies/auth-code-flow.js +310 -0
- package/build/cjs/server/authenticate/helpers/get-session-token-header.js +6 -0
- package/build/cjs/server/authenticate/helpers/reject-bot-request.js +2 -2
- package/build/cjs/server/authenticate/public/checkout/authenticate.js +1 -1
- package/build/cjs/server/authenticate/public/factory.js +14 -5
- package/build/cjs/server/authenticate/webhooks/authenticate.js +14 -5
- package/build/cjs/server/clients/admin/graphql.js +6 -8
- package/build/cjs/server/shopify-app.js +12 -6
- package/build/cjs/server/version.js +1 -1
- package/build/ts/server/__test-helpers/test-config.d.ts +36 -6
- package/build/ts/server/__test-helpers/test-config.d.ts.map +1 -1
- package/build/ts/server/__test-helpers/test-config.js +34 -6
- package/build/ts/server/__test-helpers/test-config.js.map +1 -1
- package/build/ts/server/authenticate/admin/authenticate.d.ts +8 -25
- package/build/ts/server/authenticate/admin/authenticate.d.ts.map +1 -1
- package/build/ts/server/authenticate/admin/authenticate.js +124 -488
- package/build/ts/server/authenticate/admin/authenticate.js.map +1 -1
- package/build/ts/server/authenticate/admin/billing/types.d.ts +11 -3
- package/build/ts/server/authenticate/admin/billing/types.d.ts.map +1 -1
- package/build/ts/server/authenticate/admin/helpers/create-admin-api-context.d.ts +5 -0
- package/build/ts/server/authenticate/admin/helpers/create-admin-api-context.d.ts.map +1 -0
- package/build/ts/server/authenticate/admin/helpers/create-admin-api-context.js +16 -0
- package/build/ts/server/authenticate/admin/helpers/create-admin-api-context.js.map +1 -0
- package/build/ts/server/authenticate/admin/helpers/ensure-app-is-embedded-if-required.d.ts +3 -0
- package/build/ts/server/authenticate/admin/helpers/ensure-app-is-embedded-if-required.d.ts.map +1 -0
- package/build/ts/server/authenticate/admin/helpers/ensure-app-is-embedded-if-required.js +25 -0
- package/build/ts/server/authenticate/admin/helpers/ensure-app-is-embedded-if-required.js.map +1 -0
- package/build/ts/server/authenticate/admin/helpers/ensure-session-token-search-param-if-required.d.ts +3 -0
- package/build/ts/server/authenticate/admin/helpers/ensure-session-token-search-param-if-required.d.ts.map +1 -0
- package/build/ts/server/authenticate/admin/helpers/ensure-session-token-search-param-if-required.js +23 -0
- package/build/ts/server/authenticate/admin/helpers/ensure-session-token-search-param-if-required.js.map +1 -0
- package/build/ts/server/authenticate/admin/helpers/index.d.ts +7 -0
- package/build/ts/server/authenticate/admin/helpers/index.d.ts.map +1 -1
- package/build/ts/server/authenticate/admin/helpers/index.js +7 -0
- package/build/ts/server/authenticate/admin/helpers/index.js.map +1 -1
- package/build/ts/server/authenticate/admin/helpers/redirect-to-bounce-page.d.ts +3 -0
- package/build/ts/server/authenticate/admin/helpers/redirect-to-bounce-page.d.ts.map +1 -0
- package/build/ts/server/authenticate/admin/helpers/redirect-to-bounce-page.js +16 -0
- package/build/ts/server/authenticate/admin/helpers/redirect-to-bounce-page.js.map +1 -0
- package/build/ts/server/authenticate/admin/helpers/redirect-to-shopify-or-app-root.d.ts +3 -0
- package/build/ts/server/authenticate/admin/helpers/redirect-to-shopify-or-app-root.d.ts.map +1 -0
- package/build/ts/server/authenticate/admin/helpers/redirect-to-shopify-or-app-root.js +32 -0
- package/build/ts/server/authenticate/admin/helpers/redirect-to-shopify-or-app-root.js.map +1 -0
- package/build/ts/server/authenticate/admin/helpers/trigger-after-auth-hook.d.ts +4 -0
- package/build/ts/server/authenticate/admin/helpers/trigger-after-auth-hook.d.ts.map +1 -0
- package/build/ts/server/authenticate/admin/helpers/trigger-after-auth-hook.js +28 -0
- package/build/ts/server/authenticate/admin/helpers/trigger-after-auth-hook.js.map +1 -0
- package/build/ts/server/authenticate/admin/helpers/validate-shop-and-host-params.d.ts +3 -0
- package/build/ts/server/authenticate/admin/helpers/validate-shop-and-host-params.d.ts.map +1 -0
- package/build/ts/server/authenticate/admin/helpers/validate-shop-and-host-params.js +26 -0
- package/build/ts/server/authenticate/admin/helpers/validate-shop-and-host-params.js.map +1 -0
- package/build/ts/server/authenticate/admin/strategies/auth-code-flow.d.ts +22 -0
- package/build/ts/server/authenticate/admin/strategies/auth-code-flow.d.ts.map +1 -0
- package/build/ts/server/authenticate/admin/strategies/auth-code-flow.js +323 -0
- package/build/ts/server/authenticate/admin/strategies/auth-code-flow.js.map +1 -0
- package/build/ts/server/authenticate/admin/strategies/types.d.ts +11 -0
- package/build/ts/server/authenticate/admin/strategies/types.d.ts.map +1 -0
- package/build/ts/server/authenticate/admin/strategies/types.js +3 -0
- package/build/ts/server/authenticate/admin/strategies/types.js.map +1 -0
- package/build/ts/server/authenticate/admin/types.d.ts +4 -0
- package/build/ts/server/authenticate/admin/types.d.ts.map +1 -1
- package/build/ts/server/authenticate/helpers/get-session-token-header.d.ts +1 -0
- package/build/ts/server/authenticate/helpers/get-session-token-header.d.ts.map +1 -1
- package/build/ts/server/authenticate/helpers/get-session-token-header.js +7 -1
- package/build/ts/server/authenticate/helpers/get-session-token-header.js.map +1 -1
- package/build/ts/server/authenticate/helpers/reject-bot-request.d.ts +1 -1
- package/build/ts/server/authenticate/helpers/reject-bot-request.d.ts.map +1 -1
- package/build/ts/server/authenticate/helpers/reject-bot-request.js +3 -3
- package/build/ts/server/authenticate/helpers/reject-bot-request.js.map +1 -1
- package/build/ts/server/authenticate/public/appProxy/authenticate.public.app-proxy.doc.d.ts.map +1 -1
- package/build/ts/server/authenticate/public/appProxy/authenticate.public.app-proxy.doc.js +2 -2
- package/build/ts/server/authenticate/public/appProxy/authenticate.public.app-proxy.doc.js.map +1 -1
- package/build/ts/server/authenticate/public/appProxy/types.d.ts +6 -3
- package/build/ts/server/authenticate/public/appProxy/types.d.ts.map +1 -1
- package/build/ts/server/authenticate/public/checkout/authenticate.js +1 -1
- package/build/ts/server/authenticate/public/checkout/authenticate.js.map +1 -1
- package/build/ts/server/authenticate/public/factory.d.ts +2 -1
- package/build/ts/server/authenticate/public/factory.d.ts.map +1 -1
- package/build/ts/server/authenticate/public/factory.js +10 -2
- package/build/ts/server/authenticate/public/factory.js.map +1 -1
- package/build/ts/server/authenticate/public/types.d.ts +4 -3
- package/build/ts/server/authenticate/public/types.d.ts.map +1 -1
- package/build/ts/server/authenticate/webhooks/authenticate.d.ts.map +1 -1
- package/build/ts/server/authenticate/webhooks/authenticate.js +12 -2
- package/build/ts/server/authenticate/webhooks/authenticate.js.map +1 -1
- package/build/ts/server/clients/admin/graphql.js +2 -2
- package/build/ts/server/clients/admin/graphql.js.map +1 -1
- package/build/ts/server/clients/admin/types.d.ts +51 -10
- package/build/ts/server/clients/admin/types.d.ts.map +1 -1
- package/build/ts/server/clients/storefront/types.d.ts +4 -4
- package/build/ts/server/config-types.d.ts +5 -5
- 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/shopify-app.d.ts.map +1 -1
- package/build/ts/server/shopify-app.js +5 -3
- package/build/ts/server/shopify-app.js.map +1 -1
- package/build/ts/server/types.d.ts +3 -3
- package/build/ts/server/types.d.ts.map +1 -1
- package/build/ts/server/version.d.ts +1 -1
- package/build/ts/server/version.js +1 -1
- package/package.json +4 -4
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
5
|
+
var factory = require('../../../clients/admin/factory.js');
|
|
6
|
+
var handleClientError = require('./handle-client-error.js');
|
|
7
|
+
|
|
8
|
+
function createAdminApiContext(request, session, params) {
|
|
9
|
+
return factory.adminClientFactory({
|
|
10
|
+
session,
|
|
11
|
+
params,
|
|
12
|
+
handleClientError: handleClientError.handleClientErrorFactory({
|
|
13
|
+
request
|
|
14
|
+
})
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
exports.createAdminApiContext = createAdminApiContext;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
5
|
+
var redirectToShopifyOrAppRoot = require('./redirect-to-shopify-or-app-root.js');
|
|
6
|
+
|
|
7
|
+
const ensureAppIsEmbeddedIfRequired = async (params, request) => {
|
|
8
|
+
const {
|
|
9
|
+
api,
|
|
10
|
+
logger,
|
|
11
|
+
config
|
|
12
|
+
} = params;
|
|
13
|
+
const url = new URL(request.url);
|
|
14
|
+
const shop = url.searchParams.get('shop');
|
|
15
|
+
if (api.config.isEmbeddedApp && url.searchParams.get('embedded') !== '1') {
|
|
16
|
+
logger.debug('App is not embedded, redirecting to Shopify', {
|
|
17
|
+
shop
|
|
18
|
+
});
|
|
19
|
+
await redirectToShopifyOrAppRoot.redirectToShopifyOrAppRoot(request, {
|
|
20
|
+
api,
|
|
21
|
+
logger,
|
|
22
|
+
config
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
exports.ensureAppIsEmbeddedIfRequired = ensureAppIsEmbeddedIfRequired;
|
package/build/cjs/server/authenticate/admin/helpers/ensure-session-token-search-param-if-required.js
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
5
|
+
var redirectToBouncePage = require('./redirect-to-bounce-page.js');
|
|
6
|
+
|
|
7
|
+
const SESSION_TOKEN_PARAM = 'id_token';
|
|
8
|
+
const ensureSessionTokenSearchParamIfRequired = async (params, request) => {
|
|
9
|
+
const {
|
|
10
|
+
api,
|
|
11
|
+
logger
|
|
12
|
+
} = params;
|
|
13
|
+
const url = new URL(request.url);
|
|
14
|
+
const shop = url.searchParams.get('shop');
|
|
15
|
+
const searchParamSessionToken = url.searchParams.get(SESSION_TOKEN_PARAM);
|
|
16
|
+
const isEmbedded = url.searchParams.get('embedded') === '1';
|
|
17
|
+
if (api.config.isEmbeddedApp && isEmbedded && !searchParamSessionToken) {
|
|
18
|
+
logger.debug('Missing session token in search params, going to bounce page', {
|
|
19
|
+
shop
|
|
20
|
+
});
|
|
21
|
+
redirectToBouncePage.redirectToBouncePage(params, url);
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
exports.ensureSessionTokenSearchParamIfRequired = ensureSessionTokenSearchParamIfRequired;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
5
|
+
var serverRuntime = require('@remix-run/server-runtime');
|
|
6
|
+
|
|
7
|
+
const redirectToBouncePage = (params, url) => {
|
|
8
|
+
const {
|
|
9
|
+
config
|
|
10
|
+
} = params;
|
|
11
|
+
|
|
12
|
+
// Make sure we always point to the configured app URL so it also works behind reverse proxies (that alter the Host
|
|
13
|
+
// header).
|
|
14
|
+
url.searchParams.set('shopify-reload', `${config.appUrl}${url.pathname}${url.search}`);
|
|
15
|
+
|
|
16
|
+
// eslint-disable-next-line no-warning-comments
|
|
17
|
+
// TODO Make sure this works on chrome without a tunnel (weird HTTPS redirect issue)
|
|
18
|
+
// https://github.com/orgs/Shopify/projects/6899/views/1?pane=issue&itemId=28376650
|
|
19
|
+
throw serverRuntime.redirect(`${config.auth.patchSessionTokenPath}${url.search}`);
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
exports.redirectToBouncePage = redirectToBouncePage;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
5
|
+
var serverRuntime = require('@remix-run/server-runtime');
|
|
6
|
+
|
|
7
|
+
async function redirectToShopifyOrAppRoot(request, params, responseHeaders) {
|
|
8
|
+
const {
|
|
9
|
+
api
|
|
10
|
+
} = params;
|
|
11
|
+
const url = new URL(request.url);
|
|
12
|
+
const host = api.utils.sanitizeHost(url.searchParams.get('host'));
|
|
13
|
+
const shop = api.utils.sanitizeShop(url.searchParams.get('shop'));
|
|
14
|
+
const redirectUrl = api.config.isEmbeddedApp ? await api.auth.getEmbeddedAppUrl({
|
|
15
|
+
rawRequest: request
|
|
16
|
+
}) : `/?shop=${shop}&host=${encodeURIComponent(host)}`;
|
|
17
|
+
throw serverRuntime.redirect(redirectUrl, {
|
|
18
|
+
headers: responseHeaders
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
exports.redirectToShopifyOrAppRoot = redirectToShopifyOrAppRoot;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
5
|
+
var createAdminApiContext = require('./create-admin-api-context.js');
|
|
6
|
+
|
|
7
|
+
async function triggerAfterAuthHook(params, session, request) {
|
|
8
|
+
const {
|
|
9
|
+
config,
|
|
10
|
+
logger
|
|
11
|
+
} = params;
|
|
12
|
+
if (config.hooks.afterAuth) {
|
|
13
|
+
logger.info('Running afterAuth hook');
|
|
14
|
+
await config.hooks.afterAuth({
|
|
15
|
+
session,
|
|
16
|
+
admin: createAdminApiContext.createAdminApiContext(request, session, params)
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
exports.triggerAfterAuthHook = triggerAfterAuthHook;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
5
|
+
var serverRuntime = require('@remix-run/server-runtime');
|
|
6
|
+
|
|
7
|
+
function validateShopAndHostParams(params, request) {
|
|
8
|
+
const {
|
|
9
|
+
api,
|
|
10
|
+
config,
|
|
11
|
+
logger
|
|
12
|
+
} = params;
|
|
13
|
+
if (config.isEmbeddedApp) {
|
|
14
|
+
const url = new URL(request.url);
|
|
15
|
+
const shop = api.utils.sanitizeShop(url.searchParams.get('shop'));
|
|
16
|
+
if (!shop) {
|
|
17
|
+
logger.debug('Missing or invalid shop, redirecting to login path', {
|
|
18
|
+
shop
|
|
19
|
+
});
|
|
20
|
+
throw serverRuntime.redirect(config.auth.loginPath);
|
|
21
|
+
}
|
|
22
|
+
const host = api.utils.sanitizeHost(url.searchParams.get('host'));
|
|
23
|
+
if (!host) {
|
|
24
|
+
logger.debug('Invalid host, redirecting to login path', {
|
|
25
|
+
host: url.searchParams.get('host')
|
|
26
|
+
});
|
|
27
|
+
throw serverRuntime.redirect(config.auth.loginPath);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
exports.validateShopAndHostParams = validateShopAndHostParams;
|
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
5
|
+
var shopifyApi = require('@shopify/shopify-api');
|
|
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
|
+
var redirectToShopifyOrAppRoot = require('../helpers/redirect-to-shopify-or-app-root.js');
|
|
10
|
+
require('@remix-run/server-runtime');
|
|
11
|
+
var redirectWithExitiframe = require('../helpers/redirect-with-exitiframe.js');
|
|
12
|
+
var getSessionTokenHeader = require('../../helpers/get-session-token-header.js');
|
|
13
|
+
var triggerAfterAuthHook = require('../helpers/trigger-after-auth-hook.js');
|
|
14
|
+
var validateShopAndHostParams = require('../helpers/validate-shop-and-host-params.js');
|
|
15
|
+
require('isbot');
|
|
16
|
+
|
|
17
|
+
class AuthCodeFlowStrategy {
|
|
18
|
+
constructor({
|
|
19
|
+
api,
|
|
20
|
+
config,
|
|
21
|
+
logger
|
|
22
|
+
}) {
|
|
23
|
+
this.api = void 0;
|
|
24
|
+
this.config = void 0;
|
|
25
|
+
this.logger = void 0;
|
|
26
|
+
this.api = api;
|
|
27
|
+
this.config = config;
|
|
28
|
+
this.logger = logger;
|
|
29
|
+
}
|
|
30
|
+
async respondToOAuthRequests(request) {
|
|
31
|
+
const {
|
|
32
|
+
api,
|
|
33
|
+
config
|
|
34
|
+
} = this;
|
|
35
|
+
const url = new URL(request.url);
|
|
36
|
+
const isAuthRequest = url.pathname === config.auth.path;
|
|
37
|
+
const isAuthCallbackRequest = url.pathname === config.auth.callbackPath;
|
|
38
|
+
if (isAuthRequest || isAuthCallbackRequest) {
|
|
39
|
+
const shop = api.utils.sanitizeShop(url.searchParams.get('shop'));
|
|
40
|
+
if (!shop) throw new Response('Shop param is invalid', {
|
|
41
|
+
status: 400
|
|
42
|
+
});
|
|
43
|
+
if (isAuthRequest) {
|
|
44
|
+
throw await this.handleAuthBeginRequest(request, shop);
|
|
45
|
+
} else {
|
|
46
|
+
throw await this.handleAuthCallbackRequest(request, shop);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
if (!getSessionTokenHeader.getSessionTokenHeader(request)) {
|
|
50
|
+
// This is a document request that doesn't contain a session token. We check if the app is installed.
|
|
51
|
+
// If the app isn't installed, we initiate the OAuth auth code flow.
|
|
52
|
+
// Requests with a header can only happen after the app is installed.
|
|
53
|
+
await this.ensureInstalledOnShop(request);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
async authenticate(request, session, shop) {
|
|
57
|
+
const {
|
|
58
|
+
api,
|
|
59
|
+
config,
|
|
60
|
+
logger
|
|
61
|
+
} = this;
|
|
62
|
+
if (!session) {
|
|
63
|
+
logger.debug('No session found, redirecting to OAuth', {
|
|
64
|
+
shop
|
|
65
|
+
});
|
|
66
|
+
await redirectToAuthPage.redirectToAuthPage({
|
|
67
|
+
config,
|
|
68
|
+
logger,
|
|
69
|
+
api
|
|
70
|
+
}, request, shop);
|
|
71
|
+
} else if (!session.isActive(config.scopes)) {
|
|
72
|
+
logger.debug('Found a session, but it has expired, redirecting to OAuth', {
|
|
73
|
+
shop
|
|
74
|
+
});
|
|
75
|
+
await redirectToAuthPage.redirectToAuthPage({
|
|
76
|
+
config,
|
|
77
|
+
logger,
|
|
78
|
+
api
|
|
79
|
+
}, request, shop);
|
|
80
|
+
}
|
|
81
|
+
logger.debug('Found a valid session', {
|
|
82
|
+
shop
|
|
83
|
+
});
|
|
84
|
+
return session;
|
|
85
|
+
}
|
|
86
|
+
async ensureInstalledOnShop(request) {
|
|
87
|
+
const {
|
|
88
|
+
api,
|
|
89
|
+
config,
|
|
90
|
+
logger
|
|
91
|
+
} = this;
|
|
92
|
+
validateShopAndHostParams.validateShopAndHostParams({
|
|
93
|
+
api,
|
|
94
|
+
config,
|
|
95
|
+
logger
|
|
96
|
+
}, request);
|
|
97
|
+
const url = new URL(request.url);
|
|
98
|
+
let shop = url.searchParams.get('shop');
|
|
99
|
+
|
|
100
|
+
// Ensure app is installed
|
|
101
|
+
logger.debug('Ensuring app is installed on shop', {
|
|
102
|
+
shop
|
|
103
|
+
});
|
|
104
|
+
if (!(await this.hasValidOfflineId(request))) {
|
|
105
|
+
logger.info("Could not find a shop, can't authenticate request");
|
|
106
|
+
throw new Response(undefined, {
|
|
107
|
+
status: 400,
|
|
108
|
+
statusText: 'Bad Request'
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
const offlineSession = await this.getOfflineSession(request);
|
|
112
|
+
const isEmbedded = url.searchParams.get('embedded') === '1';
|
|
113
|
+
if (!offlineSession) {
|
|
114
|
+
logger.info("Shop hasn't installed app yet, redirecting to OAuth", {
|
|
115
|
+
shop
|
|
116
|
+
});
|
|
117
|
+
if (isEmbedded) {
|
|
118
|
+
redirectWithExitiframe.redirectWithExitIframe({
|
|
119
|
+
api,
|
|
120
|
+
config,
|
|
121
|
+
logger
|
|
122
|
+
}, request, shop);
|
|
123
|
+
} else {
|
|
124
|
+
throw await beginAuth.beginAuth({
|
|
125
|
+
api,
|
|
126
|
+
config,
|
|
127
|
+
logger
|
|
128
|
+
}, request, false, shop);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
shop = shop || offlineSession.shop;
|
|
132
|
+
if (config.isEmbeddedApp && !isEmbedded) {
|
|
133
|
+
try {
|
|
134
|
+
logger.debug('Ensuring offline session is valid before embedding', {
|
|
135
|
+
shop
|
|
136
|
+
});
|
|
137
|
+
await this.testSession(offlineSession);
|
|
138
|
+
logger.debug('Offline session is still valid, embedding app', {
|
|
139
|
+
shop
|
|
140
|
+
});
|
|
141
|
+
} catch (error) {
|
|
142
|
+
await this.handleInvalidOfflineSession(error, request, shop);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
async handleAuthBeginRequest(request, shop) {
|
|
147
|
+
const {
|
|
148
|
+
api,
|
|
149
|
+
config,
|
|
150
|
+
logger
|
|
151
|
+
} = this;
|
|
152
|
+
logger.info('Handling OAuth begin request', {
|
|
153
|
+
shop
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
// If we're loading from an iframe, we need to break out of it
|
|
157
|
+
if (config.isEmbeddedApp && request.headers.get('Sec-Fetch-Dest') === 'iframe') {
|
|
158
|
+
logger.debug('Auth request in iframe detected, exiting iframe', {
|
|
159
|
+
shop
|
|
160
|
+
});
|
|
161
|
+
throw redirectWithExitiframe.redirectWithExitIframe({
|
|
162
|
+
api,
|
|
163
|
+
config,
|
|
164
|
+
logger
|
|
165
|
+
}, request, shop);
|
|
166
|
+
} else {
|
|
167
|
+
throw await beginAuth.beginAuth({
|
|
168
|
+
api,
|
|
169
|
+
config,
|
|
170
|
+
logger
|
|
171
|
+
}, request, false, shop);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
async handleAuthCallbackRequest(request, shop) {
|
|
175
|
+
const {
|
|
176
|
+
api,
|
|
177
|
+
config,
|
|
178
|
+
logger
|
|
179
|
+
} = this;
|
|
180
|
+
logger.info('Handling OAuth callback request');
|
|
181
|
+
try {
|
|
182
|
+
const {
|
|
183
|
+
session,
|
|
184
|
+
headers: responseHeaders
|
|
185
|
+
} = await api.auth.callback({
|
|
186
|
+
rawRequest: request
|
|
187
|
+
});
|
|
188
|
+
await config.sessionStorage.storeSession(session);
|
|
189
|
+
if (config.useOnlineTokens && !session.isOnline) {
|
|
190
|
+
logger.info('Requesting online access token for offline session');
|
|
191
|
+
await beginAuth.beginAuth({
|
|
192
|
+
api,
|
|
193
|
+
config,
|
|
194
|
+
logger
|
|
195
|
+
}, request, true, shop);
|
|
196
|
+
}
|
|
197
|
+
await triggerAfterAuthHook.triggerAfterAuthHook({
|
|
198
|
+
api,
|
|
199
|
+
config,
|
|
200
|
+
logger
|
|
201
|
+
}, session, request);
|
|
202
|
+
throw await redirectToShopifyOrAppRoot.redirectToShopifyOrAppRoot(request, {
|
|
203
|
+
api,
|
|
204
|
+
config,
|
|
205
|
+
logger
|
|
206
|
+
}, responseHeaders);
|
|
207
|
+
} catch (error) {
|
|
208
|
+
if (error instanceof Response) throw error;
|
|
209
|
+
throw await this.oauthCallbackError(error, request, shop);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
async getOfflineSession(request) {
|
|
213
|
+
const offlineId = await this.getOfflineSessionId(request);
|
|
214
|
+
return this.config.sessionStorage.loadSession(offlineId);
|
|
215
|
+
}
|
|
216
|
+
async hasValidOfflineId(request) {
|
|
217
|
+
return Boolean(await this.getOfflineSessionId(request));
|
|
218
|
+
}
|
|
219
|
+
async getOfflineSessionId(request) {
|
|
220
|
+
const {
|
|
221
|
+
api
|
|
222
|
+
} = this;
|
|
223
|
+
const url = new URL(request.url);
|
|
224
|
+
const shop = url.searchParams.get('shop');
|
|
225
|
+
return shop ? api.session.getOfflineId(shop) : api.session.getCurrentId({
|
|
226
|
+
isOnline: false,
|
|
227
|
+
rawRequest: request
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
async testSession(session) {
|
|
231
|
+
const {
|
|
232
|
+
api
|
|
233
|
+
} = this;
|
|
234
|
+
const client = new api.clients.Graphql({
|
|
235
|
+
session
|
|
236
|
+
});
|
|
237
|
+
await client.query({
|
|
238
|
+
data: `#graphql
|
|
239
|
+
query shopifyAppShopName {
|
|
240
|
+
shop {
|
|
241
|
+
name
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
`
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
async oauthCallbackError(error, request, shop) {
|
|
248
|
+
const {
|
|
249
|
+
logger
|
|
250
|
+
} = this;
|
|
251
|
+
logger.error('Error during OAuth callback', {
|
|
252
|
+
error: error.message
|
|
253
|
+
});
|
|
254
|
+
if (error instanceof shopifyApi.CookieNotFound) {
|
|
255
|
+
return this.handleAuthBeginRequest(request, shop);
|
|
256
|
+
}
|
|
257
|
+
if (error instanceof shopifyApi.InvalidHmacError || error instanceof shopifyApi.InvalidOAuthError) {
|
|
258
|
+
return new Response(undefined, {
|
|
259
|
+
status: 400,
|
|
260
|
+
statusText: 'Invalid OAuth Request'
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
return new Response(undefined, {
|
|
264
|
+
status: 500,
|
|
265
|
+
statusText: 'Internal Server Error'
|
|
266
|
+
});
|
|
267
|
+
}
|
|
268
|
+
async handleInvalidOfflineSession(error, request, shop) {
|
|
269
|
+
const {
|
|
270
|
+
api,
|
|
271
|
+
logger,
|
|
272
|
+
config
|
|
273
|
+
} = this;
|
|
274
|
+
if (error instanceof shopifyApi.HttpResponseError) {
|
|
275
|
+
if (error.response.code === 401) {
|
|
276
|
+
logger.info('Shop session is no longer valid, redirecting to OAuth', {
|
|
277
|
+
shop
|
|
278
|
+
});
|
|
279
|
+
throw await beginAuth.beginAuth({
|
|
280
|
+
api,
|
|
281
|
+
config,
|
|
282
|
+
logger
|
|
283
|
+
}, request, false, shop);
|
|
284
|
+
} else {
|
|
285
|
+
const message = JSON.stringify(error.response.body, null, 2);
|
|
286
|
+
logger.error(`Unexpected error during session validation: ${message}`, {
|
|
287
|
+
shop
|
|
288
|
+
});
|
|
289
|
+
throw new Response(undefined, {
|
|
290
|
+
status: error.response.code,
|
|
291
|
+
statusText: error.response.statusText
|
|
292
|
+
});
|
|
293
|
+
}
|
|
294
|
+
} else if (error instanceof shopifyApi.GraphqlQueryError) {
|
|
295
|
+
const context = {
|
|
296
|
+
shop
|
|
297
|
+
};
|
|
298
|
+
if (error.response) {
|
|
299
|
+
context.response = JSON.stringify(error.response);
|
|
300
|
+
}
|
|
301
|
+
logger.error(`Unexpected error during session validation: ${error.message}`, context);
|
|
302
|
+
throw new Response(undefined, {
|
|
303
|
+
status: 500,
|
|
304
|
+
statusText: 'Internal Server Error'
|
|
305
|
+
});
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
exports.AuthCodeFlowStrategy = AuthCodeFlowStrategy;
|
|
@@ -2,9 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
|
5
|
+
const SESSION_TOKEN_PARAM = 'id_token';
|
|
5
6
|
function getSessionTokenHeader(request) {
|
|
6
7
|
var _request$headers$get;
|
|
7
8
|
return (_request$headers$get = request.headers.get('authorization')) === null || _request$headers$get === void 0 ? void 0 : _request$headers$get.replace('Bearer ', '');
|
|
8
9
|
}
|
|
10
|
+
function getSessionTokenFromUrlParam(request) {
|
|
11
|
+
const url = new URL(request.url);
|
|
12
|
+
return url.searchParams.get(SESSION_TOKEN_PARAM);
|
|
13
|
+
}
|
|
9
14
|
|
|
15
|
+
exports.getSessionTokenFromUrlParam = getSessionTokenFromUrlParam;
|
|
10
16
|
exports.getSessionTokenHeader = getSessionTokenHeader;
|
|
@@ -8,7 +8,7 @@ function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'defau
|
|
|
8
8
|
|
|
9
9
|
var isbot__default = /*#__PURE__*/_interopDefaultLegacy(isbot);
|
|
10
10
|
|
|
11
|
-
function
|
|
11
|
+
function respondToBotRequest({
|
|
12
12
|
logger
|
|
13
13
|
}, request) {
|
|
14
14
|
if (isbot__default["default"](request.headers.get('User-Agent'))) {
|
|
@@ -20,4 +20,4 @@ function rejectBotRequest({
|
|
|
20
20
|
}
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
exports.
|
|
23
|
+
exports.respondToBotRequest = respondToBotRequest;
|
|
@@ -15,7 +15,7 @@ function authenticateCheckoutFactory(params) {
|
|
|
15
15
|
logger
|
|
16
16
|
} = params;
|
|
17
17
|
const corsHeaders = (_options$corsHeaders = options.corsHeaders) !== null && _options$corsHeaders !== void 0 ? _options$corsHeaders : [];
|
|
18
|
-
rejectBotRequest.
|
|
18
|
+
rejectBotRequest.respondToBotRequest(params, request);
|
|
19
19
|
respondToOptionsRequest.respondToOptionsRequest(params, request, corsHeaders);
|
|
20
20
|
const sessionTokenHeader = getSessionTokenHeader.getSessionTokenHeader(request);
|
|
21
21
|
logger.info('Authenticating checkout request');
|
|
@@ -2,20 +2,29 @@
|
|
|
2
2
|
|
|
3
3
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
|
5
|
-
var authenticate
|
|
6
|
-
var authenticate = require('./appProxy/authenticate.js');
|
|
5
|
+
var authenticate = require('./checkout/authenticate.js');
|
|
6
|
+
var authenticate$1 = require('./appProxy/authenticate.js');
|
|
7
7
|
|
|
8
8
|
function authenticatePublicFactory(params) {
|
|
9
9
|
const {
|
|
10
|
-
logger
|
|
10
|
+
logger,
|
|
11
|
+
config
|
|
11
12
|
} = params;
|
|
12
|
-
const authenticateCheckout = authenticate
|
|
13
|
+
const authenticateCheckout = authenticate.authenticateCheckoutFactory(params);
|
|
14
|
+
const authenticateAppProxy = authenticate$1.authenticateAppProxyFactory(params);
|
|
15
|
+
if (config.future.v3_authenticatePublic) {
|
|
16
|
+
const context = {
|
|
17
|
+
checkout: authenticateCheckout,
|
|
18
|
+
appProxy: authenticateAppProxy
|
|
19
|
+
};
|
|
20
|
+
return context;
|
|
21
|
+
}
|
|
13
22
|
const authenticatePublic = (request, options) => {
|
|
14
23
|
logger.deprecated('3.0.0', 'authenticate.public() will be deprecated in v3. Use authenticate.public.checkout() instead.');
|
|
15
24
|
return authenticateCheckout(request, options);
|
|
16
25
|
};
|
|
17
26
|
authenticatePublic.checkout = authenticateCheckout;
|
|
18
|
-
authenticatePublic.appProxy =
|
|
27
|
+
authenticatePublic.appProxy = authenticateAppProxy;
|
|
19
28
|
return authenticatePublic;
|
|
20
29
|
}
|
|
21
30
|
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
|
5
|
+
var shopifyApi = require('@shopify/shopify-api');
|
|
5
6
|
var factory = require('../../clients/admin/factory.js');
|
|
6
7
|
require('@shopify/shopify-api/runtime');
|
|
7
8
|
var handleClientError = require('../admin/helpers/handle-client-error.js');
|
|
@@ -30,11 +31,19 @@ function authenticateWebhookFactory(params) {
|
|
|
30
31
|
rawRequest: request
|
|
31
32
|
});
|
|
32
33
|
if (!check.valid) {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
34
|
+
if (check.reason === shopifyApi.WebhookValidationErrorReason.InvalidHmac) {
|
|
35
|
+
logger.debug('Webhook HMAC validation failed', check);
|
|
36
|
+
throw new Response(undefined, {
|
|
37
|
+
status: 401,
|
|
38
|
+
statusText: 'Unauthorized'
|
|
39
|
+
});
|
|
40
|
+
} else {
|
|
41
|
+
logger.debug('Webhook validation failed', check);
|
|
42
|
+
throw new Response(undefined, {
|
|
43
|
+
status: 400,
|
|
44
|
+
statusText: 'Bad Request'
|
|
45
|
+
});
|
|
46
|
+
}
|
|
38
47
|
}
|
|
39
48
|
const sessionId = api.session.getOfflineId(check.domain);
|
|
40
49
|
const session = await config.sessionStorage.loadSession(sessionId);
|
|
@@ -13,22 +13,20 @@ function graphqlClientFactory({
|
|
|
13
13
|
handleClientError,
|
|
14
14
|
session
|
|
15
15
|
}) {
|
|
16
|
-
return async function query(
|
|
17
|
-
var _options;
|
|
16
|
+
return async function query(operation, options) {
|
|
18
17
|
const client = new params.api.clients.Graphql({
|
|
19
18
|
session,
|
|
20
|
-
apiVersion:
|
|
19
|
+
apiVersion: options === null || options === void 0 ? void 0 : options.apiVersion
|
|
21
20
|
});
|
|
22
21
|
try {
|
|
23
|
-
var _options2, _options3, _options4;
|
|
24
22
|
// We convert the incoming response to a Response object to bring this client closer to the Remix client.
|
|
25
23
|
const apiResponse = await client.query({
|
|
26
24
|
data: {
|
|
27
|
-
query,
|
|
28
|
-
variables:
|
|
25
|
+
query: operation,
|
|
26
|
+
variables: options === null || options === void 0 ? void 0 : options.variables
|
|
29
27
|
},
|
|
30
|
-
tries:
|
|
31
|
-
extraHeaders:
|
|
28
|
+
tries: options === null || options === void 0 ? void 0 : options.tries,
|
|
29
|
+
extraHeaders: options === null || options === void 0 ? void 0 : options.headers
|
|
32
30
|
});
|
|
33
31
|
return new Response(JSON.stringify(apiResponse.body), {
|
|
34
32
|
headers: runtime.flatHeaders(apiResponse.headers)
|
|
@@ -7,8 +7,8 @@ var shopifyApi = require('@shopify/shopify-api');
|
|
|
7
7
|
var types = require('./types.js');
|
|
8
8
|
var version = require('./version.js');
|
|
9
9
|
var register = require('./authenticate/webhooks/register.js');
|
|
10
|
-
var authenticate
|
|
11
|
-
var authenticate = require('./authenticate/webhooks/authenticate.js');
|
|
10
|
+
var authenticate = require('./authenticate/admin/authenticate.js');
|
|
11
|
+
var authenticate$1 = require('./authenticate/webhooks/authenticate.js');
|
|
12
12
|
var overrideLogger = require('./override-logger.js');
|
|
13
13
|
var addResponseHeaders = require('./authenticate/helpers/add-response-headers.js');
|
|
14
14
|
require('isbot');
|
|
@@ -16,6 +16,7 @@ var login = require('./authenticate/login/login.js');
|
|
|
16
16
|
var factory$1 = require('./unauthenticated/admin/factory.js');
|
|
17
17
|
var factory = require('./authenticate/public/factory.js');
|
|
18
18
|
var factory$2 = require('./unauthenticated/storefront/factory.js');
|
|
19
|
+
var authCodeFlow = require('./authenticate/admin/strategies/auth-code-flow.js');
|
|
19
20
|
|
|
20
21
|
/**
|
|
21
22
|
* Creates an object your app will use to interact with Shopify.
|
|
@@ -49,15 +50,19 @@ function shopifyApp(appConfig) {
|
|
|
49
50
|
config,
|
|
50
51
|
logger
|
|
51
52
|
};
|
|
52
|
-
const oauth = new
|
|
53
|
+
const oauth = new authCodeFlow.AuthCodeFlowStrategy(params);
|
|
54
|
+
const authStrategy = authenticate.authStrategyFactory({
|
|
55
|
+
...params,
|
|
56
|
+
strategy: oauth
|
|
57
|
+
});
|
|
53
58
|
const shopify = {
|
|
54
59
|
sessionStorage: config.sessionStorage,
|
|
55
60
|
addDocumentResponseHeaders: addResponseHeaders.addDocumentResponseHeadersFactory(params),
|
|
56
61
|
registerWebhooks: register.registerWebhooksFactory(params),
|
|
57
62
|
authenticate: {
|
|
58
|
-
admin:
|
|
63
|
+
admin: authStrategy,
|
|
59
64
|
public: factory.authenticatePublicFactory(params),
|
|
60
|
-
webhook: authenticate.authenticateWebhookFactory(params)
|
|
65
|
+
webhook: authenticate$1.authenticateWebhookFactory(params)
|
|
61
66
|
},
|
|
62
67
|
unauthenticated: {
|
|
63
68
|
admin: factory$1.unauthenticatedAdminContextFactory(params),
|
|
@@ -101,7 +106,8 @@ function deriveApi(appConfig) {
|
|
|
101
106
|
userAgentPrefix,
|
|
102
107
|
isEmbeddedApp: (_appConfig$isEmbedded = appConfig.isEmbeddedApp) !== null && _appConfig$isEmbedded !== void 0 ? _appConfig$isEmbedded : true,
|
|
103
108
|
apiVersion: (_appConfig$apiVersion = appConfig.apiVersion) !== null && _appConfig$apiVersion !== void 0 ? _appConfig$apiVersion : shopifyApi.LATEST_API_VERSION,
|
|
104
|
-
isCustomStoreApp: appConfig.distribution === types.AppDistribution.ShopifyAdmin
|
|
109
|
+
isCustomStoreApp: appConfig.distribution === types.AppDistribution.ShopifyAdmin,
|
|
110
|
+
future: {}
|
|
105
111
|
});
|
|
106
112
|
}
|
|
107
113
|
function deriveConfig(appConfig, apiConfig) {
|