UNPKG

@shopify/shopify-app-react-router

Version:

Shopify React Router - to simplify the building of Shopify Apps with React Router

101 lines (97 loc) 4.07 kB
'use strict'; var factory$1 = require('../../../clients/admin/factory.js'); var factory = require('../../../clients/storefront/factory.js'); function authenticateAppProxyFactory(params) { const { api, config, logger } = params; return async function authenticate(request) { const url = new URL(request.url); const shop = url.searchParams.get('shop'); logger.info('Authenticating app proxy request', { shop }); if (!(await validateAppProxyHmac(params, url))) { logger.info('App proxy request has invalid signature', { shop }); throw new Response(undefined, { status: 400, statusText: 'Bad Request', }); } const sessionId = api.session.getOfflineId(shop); const session = await config.sessionStorage.loadSession(sessionId); if (!session) { logger.debug('Could not find offline session, returning empty context', { shop, ...Object.fromEntries(url.searchParams.entries()), }); const context = { liquid, session: undefined, admin: undefined, storefront: undefined, }; return context; } const context = { liquid, session, admin: factory$1.adminClientFactory({ params, session }), storefront: factory.storefrontClientFactory({ params, session }), }; return context; }; } const liquid = (body, initAndOptions) => { const processedBody = processLiquidBody(body); if (typeof initAndOptions !== 'object') { return new Response(processedBody, { status: initAndOptions || 200, headers: { 'Content-Type': 'application/liquid', }, }); } const { layout, ...responseInit } = initAndOptions || {}; const responseBody = layout === false ? `{% layout none %} ${processedBody}` : processedBody; const headers = new Headers(responseInit.headers); headers.set('Content-Type', 'application/liquid'); return new Response(responseBody, { ...responseInit, headers, }); }; async function validateAppProxyHmac(params, url) { const { api, logger } = params; try { let searchParams = new URLSearchParams(url.search); if (!searchParams.get('index')) { searchParams.delete('index'); } let isValid = await api.utils.validateHmac(Object.fromEntries(searchParams.entries()), { signator: 'appProxy' }); if (!isValid) { const cleanPath = url.pathname .replace(/^\//, '') .replace(/\/$/, '') .replaceAll('/', '.'); const data = `routes%2F${cleanPath}`; searchParams = new URLSearchParams(`?_data=${data}&${searchParams.toString().replace(/^\?/, '')}`); isValid = await api.utils.validateHmac(Object.fromEntries(searchParams.entries()), { signator: 'appProxy' }); if (!isValid) { const searchParams = new URLSearchParams(`?_data=${data}._index&${url.search.replace(/^\?/, '')}`); isValid = await api.utils.validateHmac(Object.fromEntries(searchParams.entries()), { signator: 'appProxy' }); } } return isValid; } catch (error) { const shop = url.searchParams.get('shop'); logger.info(error.message, { shop }); throw new Response(undefined, { status: 400, statusText: 'Bad Request' }); } } function processLiquidBody(body) { return (body // Add trailing slashes to relative form action URLs .replaceAll(/<(form[^>]+)action="(\/[^"?]+)(\?[^"]+)?">/g, '<$1action="$2/$3">') // Add trailing slashes to relative link href URLs .replaceAll(/<(a[^>]+)href="(\/[^"?]+)(\?[^"]+)?">/g, '<$1href="$2/$3">')); } exports.authenticateAppProxyFactory = authenticateAppProxyFactory; //# sourceMappingURL=authenticate.js.map