UNPKG

@shopify/shopify-app-remix

Version:

Shopify Remix - to simplify the building of Shopify Apps with Remix

154 lines (150 loc) 7.73 kB
'use strict'; var ensureCorsHeaders = require('../helpers/ensure-cors-headers.js'); var validateSessionToken = require('../helpers/validate-session-token.js'); var getSessionTokenHeader = require('../helpers/get-session-token-header.js'); var rejectBotRequest = require('../helpers/reject-bot-request.js'); var respondToOptionsRequest = require('../helpers/respond-to-options-request.js'); require('@remix-run/server-runtime'); var getShopFromRequest = require('../helpers/get-shop-from-request.js'); var cancel = require('./billing/cancel.js'); var require$1 = require('./billing/require.js'); var request = require('./billing/request.js'); var check = require('./billing/check.js'); var createUsageRecord = require('./billing/create-usage-record.js'); var updateUsageSubscriptionCappedAmount = require('./billing/update-usage-subscription-capped-amount.js'); var createAdminApiContext = require('./helpers/create-admin-api-context.js'); var ensureAppIsEmbeddedIfRequired = require('./helpers/ensure-app-is-embedded-if-required.js'); var ensureSessionTokenSearchParamIfRequired = require('./helpers/ensure-session-token-search-param-if-required.js'); require('@shopify/shopify-api'); var redirect = require('./helpers/redirect.js'); var renderAppBridge = require('./helpers/render-app-bridge.js'); var validateShopAndHostParams = require('./helpers/validate-shop-and-host-params.js'); var factory = require('./scope/factory.js'); function authStrategyFactory({ strategy, ...params }) { const { api, logger, config } = params; async function respondToBouncePageRequest(request) { const url = new URL(request.url); if (url.pathname === config.auth.patchSessionTokenPath) { logger.debug('Rendering bounce page', { shop: getShopFromRequest.getShopFromRequest(request), }); throw renderAppBridge.renderAppBridge({ config}, request); } } async function respondToExitIframeRequest(request) { const url = new URL(request.url); if (url.pathname === config.auth.exitIframePath) { const destination = url.searchParams.get('exitIframe'); logger.debug('Rendering exit iframe page', { shop: getShopFromRequest.getShopFromRequest(request), destination, }); throw renderAppBridge.renderAppBridge({ config}, request, { url: destination }); } } function createContext(request$1, session, authStrategy, sessionToken) { let context = { admin: createAdminApiContext.createAdminApiContext(session, params, authStrategy.handleClientError(request$1)), billing: { require: require$1.requireBillingFactory(params, request$1, session), check: check.checkBillingFactory(params, request$1, session), request: request.requestBillingFactory(params, request$1, session), cancel: cancel.cancelBillingFactory(params, request$1, session), createUsageRecord: createUsageRecord.createUsageRecordFactory(params, request$1, session), updateUsageCappedAmount: updateUsageSubscriptionCappedAmount.updateUsageCappedAmountFactory(params, request$1, session), }, session, cors: ensureCorsHeaders.ensureCORSHeadersFactory(params, request$1), }; context = addEmbeddedFeatures(context, request$1, session, sessionToken); context = addScopesFeatures(context); return context; } function addEmbeddedFeatures(context, request, session, sessionToken) { if (config.isEmbeddedApp) { return { ...context, sessionToken, redirect: redirect.redirectFactory(params, request, session.shop), }; } return context; } function addScopesFeatures(context) { return { ...context, scopes: factory.scopesApiFactory(params, context.session, context.admin), }; } return async function authenticateAdmin(request) { try { rejectBotRequest.respondToBotRequest(params, request); respondToOptionsRequest.respondToOptionsRequest(params, request); await respondToBouncePageRequest(request); await respondToExitIframeRequest(request); await strategy.respondToOAuthRequests(request); // If this is a valid request, but it doesn't have a session token header, this is a document request. We need to // ensure we're embedded if needed and we have the information needed to load the session. if (!getSessionTokenHeader.getSessionTokenHeader(request)) { validateShopAndHostParams.validateShopAndHostParams(params, request); await ensureAppIsEmbeddedIfRequired.ensureAppIsEmbeddedIfRequired(params, request); await ensureSessionTokenSearchParamIfRequired.ensureSessionTokenSearchParamIfRequired(params, request); } logger.info('Authenticating admin request', { shop: getShopFromRequest.getShopFromRequest(request), }); const { payload, shop, sessionId, sessionToken } = await getSessionTokenContext(params, request); logger.debug('Loading session from storage', { shop, sessionId }); const existingSession = sessionId ? await config.sessionStorage.loadSession(sessionId) : undefined; const session = await strategy.authenticate(request, { session: existingSession, sessionToken, shop, }); return createContext(request, session, strategy, payload); } catch (errorOrResponse) { if (errorOrResponse instanceof Response) { logger.debug('Authenticate returned a response', { shop: getShopFromRequest.getShopFromRequest(request), }); ensureCorsHeaders.ensureCORSHeadersFactory(params, request)(errorOrResponse); } throw errorOrResponse; } }; } async function getSessionTokenContext(params, request) { const { api, config, logger } = params; const headerSessionToken = getSessionTokenHeader.getSessionTokenHeader(request); const searchParamSessionToken = getSessionTokenHeader.getSessionTokenFromUrlParam(request); const sessionToken = (headerSessionToken || searchParamSessionToken); logger.debug('Attempting to authenticate session token', { shop: getShopFromRequest.getShopFromRequest(request), sessionToken: JSON.stringify({ header: headerSessionToken, search: searchParamSessionToken, }), }); if (config.isEmbeddedApp) { const payload = await validateSessionToken.validateSessionToken(params, request, sessionToken); const dest = new URL(payload.dest); const shop = dest.hostname; logger.debug('Session token is valid - authenticated', { shop, payload }); const sessionId = config.useOnlineTokens ? api.session.getJwtSessionId(shop, payload.sub) : api.session.getOfflineId(shop); return { shop, payload, sessionId, sessionToken }; } const url = new URL(request.url); const shop = url.searchParams.get('shop'); const sessionId = await api.session.getCurrentId({ isOnline: config.useOnlineTokens, rawRequest: request, }); return { shop, sessionId, payload: undefined, sessionToken }; } exports.authStrategyFactory = authStrategyFactory; //# sourceMappingURL=authenticate.js.map