From 49672a1e4d268683feb67a574429b910417100c1 Mon Sep 17 00:00:00 2001 From: Fabien O'Carroll Date: Tue, 3 Sep 2019 12:39:00 +0800 Subject: [PATCH] Updated members service to use magic-link signin no-issue --- core/frontend/helpers/ghost_head.js | 1 - core/server/public/members-theme-bindings.js | 896 ------------------- core/server/public/members.js | 45 +- core/server/services/members/api.js | 170 +--- core/server/services/members/index.js | 11 +- core/server/web/api/canary/members/app.js | 8 +- core/server/web/api/v2/members/app.js | 8 +- package.json | 5 +- yarn.lock | 151 +--- 9 files changed, 89 insertions(+), 1206 deletions(-) delete mode 100644 core/server/public/members-theme-bindings.js diff --git a/core/frontend/helpers/ghost_head.js b/core/frontend/helpers/ghost_head.js index e084a095cb..058f4f170b 100644 --- a/core/frontend/helpers/ghost_head.js +++ b/core/frontend/helpers/ghost_head.js @@ -57,7 +57,6 @@ function getAjaxHelper(clientId, clientSecret) { function getMembersHelper() { return ` - `; } diff --git a/core/server/public/members-theme-bindings.js b/core/server/public/members-theme-bindings.js deleted file mode 100644 index f872ba7921..0000000000 --- a/core/server/public/members-theme-bindings.js +++ /dev/null @@ -1,896 +0,0 @@ -(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.MembersThemeBindings = f()}})(function(){var define,module,exports;return (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i -1 && value % 1 == 0 && value < length); -} -module.exports = isIndex; - -//# sourceURL=/home/donny/usr/src/ghost.org/Members/node_modules/lodash/_isIndex.js -},{}],19:[function(require,module,exports){ -"use strict"; -var objectProto = Object.prototype; -function isPrototype(value) { - var Ctor = value && value.constructor, - proto = (typeof Ctor == 'function' && Ctor.prototype) || objectProto; - return value === proto; -} -module.exports = isPrototype; - -//# sourceURL=/home/donny/usr/src/ghost.org/Members/node_modules/lodash/_isPrototype.js -},{}],20:[function(require,module,exports){ -"use strict"; -var overArg = require('./_overArg'); -var nativeKeys = overArg(Object.keys, Object); -module.exports = nativeKeys; - -//# sourceURL=/home/donny/usr/src/ghost.org/Members/node_modules/lodash/_nativeKeys.js -},{"./_overArg":23}],21:[function(require,module,exports){ -"use strict"; -var freeGlobal = require('./_freeGlobal'); -var freeExports = typeof exports == 'object' && exports && !exports.nodeType && exports; -var freeModule = freeExports && typeof module == 'object' && module && !module.nodeType && module; -var moduleExports = freeModule && freeModule.exports === freeExports; -var freeProcess = moduleExports && freeGlobal.process; -var nodeUtil = (function() { - try { - var types = freeModule && freeModule.require && freeModule.require('util').types; - if (types) { - return types; - } - return freeProcess && freeProcess.binding && freeProcess.binding('util'); - } catch (e) {} -}()); -module.exports = nodeUtil; - -//# sourceURL=/home/donny/usr/src/ghost.org/Members/node_modules/lodash/_nodeUtil.js -},{"./_freeGlobal":16}],22:[function(require,module,exports){ -"use strict"; -var objectProto = Object.prototype; -var nativeObjectToString = objectProto.toString; -function objectToString(value) { - return nativeObjectToString.call(value); -} -module.exports = objectToString; - -//# sourceURL=/home/donny/usr/src/ghost.org/Members/node_modules/lodash/_objectToString.js -},{}],23:[function(require,module,exports){ -"use strict"; -function overArg(func, transform) { - return function(arg) { - return func(transform(arg)); - }; -} -module.exports = overArg; - -//# sourceURL=/home/donny/usr/src/ghost.org/Members/node_modules/lodash/_overArg.js -},{}],24:[function(require,module,exports){ -"use strict"; -var freeGlobal = require('./_freeGlobal'); -var freeSelf = typeof self == 'object' && self && self.Object === Object && self; -var root = freeGlobal || freeSelf || Function('return this')(); -module.exports = root; - -//# sourceURL=/home/donny/usr/src/ghost.org/Members/node_modules/lodash/_root.js -},{"./_freeGlobal":16}],25:[function(require,module,exports){ -"use strict"; -module.exports = require('./forEach'); - -//# sourceURL=/home/donny/usr/src/ghost.org/Members/node_modules/lodash/each.js -},{"./forEach":26}],26:[function(require,module,exports){ -"use strict"; -var arrayEach = require('./_arrayEach'), - baseEach = require('./_baseEach'), - castFunction = require('./_castFunction'), - isArray = require('./isArray'); -function forEach(collection, iteratee) { - var func = isArray(collection) ? arrayEach : baseEach; - return func(collection, castFunction(iteratee)); -} -module.exports = forEach; - -//# sourceURL=/home/donny/usr/src/ghost.org/Members/node_modules/lodash/forEach.js -},{"./_arrayEach":2,"./_baseEach":4,"./_castFunction":13,"./isArray":29}],27:[function(require,module,exports){ -"use strict"; -function identity(value) { - return value; -} -module.exports = identity; - -//# sourceURL=/home/donny/usr/src/ghost.org/Members/node_modules/lodash/identity.js -},{}],28:[function(require,module,exports){ -"use strict"; -var baseIsArguments = require('./_baseIsArguments'), - isObjectLike = require('./isObjectLike'); -var objectProto = Object.prototype; -var hasOwnProperty = objectProto.hasOwnProperty; -var propertyIsEnumerable = objectProto.propertyIsEnumerable; -var isArguments = baseIsArguments(function() { - return arguments; -}()) ? baseIsArguments : function(value) { - return isObjectLike(value) && hasOwnProperty.call(value, 'callee') && !propertyIsEnumerable.call(value, 'callee'); -}; -module.exports = isArguments; - -//# sourceURL=/home/donny/usr/src/ghost.org/Members/node_modules/lodash/isArguments.js -},{"./_baseIsArguments":8,"./isObjectLike":35}],29:[function(require,module,exports){ -"use strict"; -var isArray = Array.isArray; -module.exports = isArray; - -//# sourceURL=/home/donny/usr/src/ghost.org/Members/node_modules/lodash/isArray.js -},{}],30:[function(require,module,exports){ -"use strict"; -var isFunction = require('./isFunction'), - isLength = require('./isLength'); -function isArrayLike(value) { - return value != null && isLength(value.length) && !isFunction(value); -} -module.exports = isArrayLike; - -//# sourceURL=/home/donny/usr/src/ghost.org/Members/node_modules/lodash/isArrayLike.js -},{"./isFunction":32,"./isLength":33}],31:[function(require,module,exports){ -"use strict"; -var root = require('./_root'), - stubFalse = require('./stubFalse'); -var freeExports = typeof exports == 'object' && exports && !exports.nodeType && exports; -var freeModule = freeExports && typeof module == 'object' && module && !module.nodeType && module; -var moduleExports = freeModule && freeModule.exports === freeExports; -var Buffer = moduleExports ? root.Buffer : undefined; -var nativeIsBuffer = Buffer ? Buffer.isBuffer : undefined; -var isBuffer = nativeIsBuffer || stubFalse; -module.exports = isBuffer; - -//# sourceURL=/home/donny/usr/src/ghost.org/Members/node_modules/lodash/isBuffer.js -},{"./_root":24,"./stubFalse":38}],32:[function(require,module,exports){ -"use strict"; -var baseGetTag = require('./_baseGetTag'), - isObject = require('./isObject'); -var asyncTag = '[object AsyncFunction]', - funcTag = '[object Function]', - genTag = '[object GeneratorFunction]', - proxyTag = '[object Proxy]'; -function isFunction(value) { - if (!isObject(value)) { - return false; - } - var tag = baseGetTag(value); - return tag == funcTag || tag == genTag || tag == asyncTag || tag == proxyTag; -} -module.exports = isFunction; - -//# sourceURL=/home/donny/usr/src/ghost.org/Members/node_modules/lodash/isFunction.js -},{"./_baseGetTag":7,"./isObject":34}],33:[function(require,module,exports){ -"use strict"; -var MAX_SAFE_INTEGER = 9007199254740991; -function isLength(value) { - return typeof value == 'number' && value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER; -} -module.exports = isLength; - -//# sourceURL=/home/donny/usr/src/ghost.org/Members/node_modules/lodash/isLength.js -},{}],34:[function(require,module,exports){ -"use strict"; -function isObject(value) { - var type = typeof value; - return value != null && (type == 'object' || type == 'function'); -} -module.exports = isObject; - -//# sourceURL=/home/donny/usr/src/ghost.org/Members/node_modules/lodash/isObject.js -},{}],35:[function(require,module,exports){ -"use strict"; -function isObjectLike(value) { - return value != null && typeof value == 'object'; -} -module.exports = isObjectLike; - -//# sourceURL=/home/donny/usr/src/ghost.org/Members/node_modules/lodash/isObjectLike.js -},{}],36:[function(require,module,exports){ -"use strict"; -var baseIsTypedArray = require('./_baseIsTypedArray'), - baseUnary = require('./_baseUnary'), - nodeUtil = require('./_nodeUtil'); -var nodeIsTypedArray = nodeUtil && nodeUtil.isTypedArray; -var isTypedArray = nodeIsTypedArray ? baseUnary(nodeIsTypedArray) : baseIsTypedArray; -module.exports = isTypedArray; - -//# sourceURL=/home/donny/usr/src/ghost.org/Members/node_modules/lodash/isTypedArray.js -},{"./_baseIsTypedArray":9,"./_baseUnary":12,"./_nodeUtil":21}],37:[function(require,module,exports){ -"use strict"; -var arrayLikeKeys = require('./_arrayLikeKeys'), - baseKeys = require('./_baseKeys'), - isArrayLike = require('./isArrayLike'); -function keys(object) { - return isArrayLike(object) ? arrayLikeKeys(object) : baseKeys(object); -} -module.exports = keys; - -//# sourceURL=/home/donny/usr/src/ghost.org/Members/node_modules/lodash/keys.js -},{"./_arrayLikeKeys":3,"./_baseKeys":10,"./isArrayLike":30}],38:[function(require,module,exports){ -"use strict"; -function stubFalse() { - return false; -} -module.exports = stubFalse; - -//# sourceURL=/home/donny/usr/src/ghost.org/Members/node_modules/lodash/stubFalse.js -},{}],39:[function(require,module,exports){ -"use strict"; -module.exports = function(n) { - var t = {}, - e = []; - n = n || this, n.on = function(e, r, l) { - return (t[e] = t[e] || []).push([r, l]), n; - }, n.off = function(r, l) { - r || (t = {}); - for (var o = t[r] || e, - u = o.length = l ? o.length : 0; u--; ) - l == o[u][0] && o.splice(u, 1); - return n; - }, n.emit = function(r) { - for (var l, - o = t[r] || e, - u = o.length > 0 ? o.slice(0, o.length) : o, - i = 0; l = u[i++]; ) - l[0].apply(l[1], e.slice.call(arguments, 1)); - return n; - }; -}; - -//# sourceURL=/home/donny/usr/src/ghost.org/Members/node_modules/minivents/dist/minivents.commonjs.min.js -},{}],40:[function(require,module,exports){ -"use strict"; -var gatewayApi = require('@tryghost/members-gateway-api'); -module.exports = function layer2(options) { - var authUrl = (options.membersUrl + "/auth"); - var gatewayUrl = (options.membersUrl + "/gateway"); - var container = options.container; - var members = gatewayApi({ - gatewayUrl: gatewayUrl, - container: container - }); - function postMessage(frame, data) { - var origin = new URL(frame.getAttribute('src')).origin; - frame.contentWindow.postMessage(data, origin); - } - var loadAuth = loadFrame(authUrl, container).then(function(frame) { - frame.style.position = 'fixed'; - frame.style.width = '100%'; - frame.style.height = '100%'; - frame.style.background = 'transparent'; - frame.style.top = '0'; - frame.style['z-index'] = '9999'; - return frame; - }); - function openAuth(hash) { - var query = arguments[1] !== (void 0) ? arguments[1] : ''; - return loadAuth.then(function(frame) { - return new Promise(function(resolve) { - postMessage(frame, { - hash: hash, - query: query - }); - frame.style.display = 'block'; - window.addEventListener('message', function messageListener(event) { - if (event.source !== frame.contentWindow) { - return; - } - if (!event.data || event.data.msg !== 'pls-close-auth-popup') { - return; - } - window.removeEventListener('message', messageListener); - frame.style.display = 'none'; - resolve(!!event.data.success); - }); - }); - }); - } - function resetPassword($__0) { - var token = $__0.token; - var query = ("token=" + token); - return openAuth('reset-password', query); - } - function signin() { - return openAuth('signin'); - } - function upgrade() { - return openAuth('upgrade'); - } - function signup() { - var coupon = (arguments[0] !== (void 0) ? arguments[0] : {}).coupon; - var query = ("coupon=" + coupon); - return openAuth('signup', query); - } - function getToken($__0) { - var $__1 = $__0, - audience = $__1.audience, - fresh = $__1.fresh; - return members.getToken({ - audience: audience, - fresh: fresh - }); - } - function getSSRToken() { - var fresh = (arguments[0] !== (void 0) ? arguments[0] : {}).fresh; - return members.getConfig().then(function($__1) { - var issuer = $__1.issuer; - return members.getToken({ - audience: issuer, - fresh: fresh - }); - }); - } - function signout() { - return members.signout(); - } - return Object.assign(members.bus, { - getToken: getToken, - getSSRToken: getSSRToken, - signout: signout, - signin: signin, - signup: signup, - upgrade: upgrade, - resetPassword: resetPassword - }); -}; -function loadFrame(src) { - var container = arguments[1] !== (void 0) ? arguments[1] : document.body; - return new Promise(function(resolve) { - var frame = document.createElement('iframe'); - frame.style.display = 'none'; - frame.src = src; - frame.onload = function() { - resolve(frame); - }; - container.appendChild(frame); - }); -} - -//# sourceURL=/home/donny/usr/src/ghost.org/Members/node_modules/@tryghost/members-browser-auth/index.js -},{"@tryghost/members-gateway-api":41}],41:[function(require,module,exports){ -"use strict"; -var gatewayProtocol = require('@tryghost/members-gateway-protocol'); -var events = require('minivents'); -module.exports = function layer1(options) { - var members = { - getToken: getToken, - getConfig: getConfig, - signout: signout, - signin: signin, - signup: signup, - requestPasswordReset: requestPasswordReset, - resetPassword: resetPassword, - bus: new events() - }; - var loadGateway = loadFrame(options.gatewayUrl, options.container).then(function(frame) { - var gateway = gatewayProtocol(frame); - var init = gatewayFn('init'); - gateway.listen(function(data) { - members.bus.emit(data.event, data.payload); - }); - return init(gateway).then(function() { - return gateway; - }); - }); - function getToken($__0) { - var $__1 = $__0, - audience = $__1.audience, - fresh = $__1.fresh; - return loadGateway.then(gatewayFn('getToken', { - audience: audience, - fresh: fresh - })); - } - function getConfig() { - return loadGateway.then(gatewayFn('getConfig')); - } - function signout() { - return loadGateway.then(gatewayFn('signout')); - } - function signin($__0) { - var $__1 = $__0, - email = $__1.email, - password = $__1.password; - return loadGateway.then(gatewayFn('signin', { - email: email, - password: password - })); - } - function signup($__0) { - var $__1 = $__0, - name = $__1.name, - email = $__1.email, - password = $__1.password; - return loadGateway.then(gatewayFn('signin', { - name: name, - email: email, - password: password - })); - } - function requestPasswordReset($__0) { - var email = $__0.email; - return loadGateway.then(gatewayFn('request-password-reset', {email: email})); - } - function resetPassword($__0) { - var $__1 = $__0, - token = $__1.token, - password = $__1.password; - return loadGateway.then(gatewayFn('reset-password', { - token: token, - password: password - })); - } - return members; -}; -function gatewayFn(method) { - var opts = arguments[1] !== (void 0) ? arguments[1] : {}; - return function(gateway) { - return new Promise(function(resolve, reject) { - gateway.call(method, opts, function(err, res) { - if (err) { - reject(err); - } - resolve(res); - }); - }); - }; -} -function loadFrame(src) { - var container = arguments[1] !== (void 0) ? arguments[1] : document.body; - return new Promise(function(resolve) { - var frame = document.createElement('iframe'); - frame.style.display = 'none'; - frame.src = src; - frame.onload = function() { - resolve(frame); - }; - container.appendChild(frame); - }); -} - -//# sourceURL=/home/donny/usr/src/ghost.org/Members/node_modules/@tryghost/members-gateway-api/index.js -},{"@tryghost/members-gateway-protocol":42,"minivents":39}],42:[function(require,module,exports){ -"use strict"; -module.exports = function layer0(frame) { - var getuid = (function(i) { - return function() { - return i += 1; - }; - })(1); - var origin = new URL(frame.getAttribute('src')).origin; - var handlers = {}; - var listener = null; - window.addEventListener('message', function(event) { - if (event.origin !== origin) { - return; - } - if (!event.data || !event.data.uid) { - if (event.data.event) { - return listener && listener(event.data); - } - return; - } - var handler = handlers[event.data.uid]; - if (!handler) { - return; - } - delete handlers[event.data.uid]; - handler(event.data.error, event.data.data); - }); - function call(method, options, cb) { - var uid = getuid(); - var data = { - uid: uid, - method: method, - options: options - }; - handlers[uid] = cb; - frame.contentWindow.postMessage(data, origin); - } - function listen(fn) { - if (listener) { - return false; - } - listener = fn; - return true; - } - return { - call: call, - listen: listen - }; -}; - -//# sourceURL=/home/donny/usr/src/ghost.org/Members/node_modules/@tryghost/members-gateway-protocol/index.js -},{}],43:[function(require,module,exports){ -"use strict"; -var each = require('lodash/each'); -var browserAuth = require('@tryghost/members-browser-auth'); -module.exports.init = init; -function init($__0) { - var $__1 = $__0, - membersUrl = $__1.membersUrl, - ssrUrl = $__1.ssrUrl; - var auth = browserAuth({membersUrl: membersUrl}); - var $__2 = window.location.hash.match(/^#([^?]+)\??(.*)$/) || [], - hashMatch = $__2[0], - hash = $__2[1], - query = $__2[2]; - if (hashMatch && hash === 'reset-password') { - var $__3 = query.match(/token=([a-zA-Z0-9-_]+.[a-zA-Z0-9-_]+.[a-zA-Z0-9-_]+)/) || [], - tokenMatch = $__3[0], - token = $__3[1]; - if (tokenMatch) { - return auth.resetPassword({token: token}).then((function(success) { - window.location.hash = ''; - return success; - })).then(reload); - } - } - auth.on('signedin', function() { - auth.getSSRToken({fresh: true}).then(function(token) { - createSession(token, ssrUrl); - }); - }); - auth.on('signedout', function() { - destroySession(); - }); - function signout() { - auth.signout().then((function() { - return destroySession(ssrUrl); - })).then(reload); - } - function signin() { - auth.signin().then((function() { - return auth.getSSRToken({fresh: true}).then(function(token) { - return createSession(token, ssrUrl); - }); - })).then(reload); - } - function signup($__4) { - var $__6; - var $__5 = $__4, - coupon = ($__6 = $__5.coupon) === void 0 ? '' : $__6; - auth.signup({coupon: coupon}).then((function() { - return auth.getSSRToken({fresh: true}).then(function(token) { - return createSession(token, ssrUrl); - }); - })).then(reload); - } - function upgrade() { - auth.upgrade().then((function() { - return auth.getSSRToken({fresh: true}).then(function(token) { - return createSession(token, ssrUrl); - }); - })).then(reload); - } - var signinEls = document.querySelectorAll('[data-members-signin]'); - var signupEls = document.querySelectorAll('[data-members-signup]'); - var upgradeEls = document.querySelectorAll('[data-members-upgrade]'); - var signoutEls = document.querySelectorAll('[data-members-signout]'); - each(signinEls, (function(el) { - el.addEventListener('click', (function(event) { - event.preventDefault(); - signin(); - })); - })); - each(signupEls, (function(el) { - el.addEventListener('click', (function(event) { - event.preventDefault(); - var coupon = el.dataset.membersCoupon; - signup({coupon: coupon}); - })); - })); - each(upgradeEls, (function(el) { - el.addEventListener('click', (function(event) { - event.preventDefault(); - upgrade(); - })); - })); - each(signoutEls, (function(el) { - el.addEventListener('click', (function(event) { - event.preventDefault(); - signout(); - })); - })); -} -function reload(success) { - if (success) { - window.location.reload(); - } -} -function createSession(token, ssrUrl) { - return fetch(ssrUrl, { - method: 'post', - credentials: 'include', - body: token - }).then(function(res) { - return !!res.ok; - }); -} -function destroySession(ssrUrl) { - return fetch(ssrUrl, {method: 'delete'}).then(function(res) { - return !!res.ok; - }); -} - -//# sourceURL=/home/donny/usr/src/ghost.org/Members/packages/members-theme-bindings/index.js -},{"@tryghost/members-browser-auth":40,"lodash/each":25}]},{},[43])(43) -}); diff --git a/core/server/public/members.js b/core/server/public/members.js index a607e74d50..9dc903f527 100644 --- a/core/server/public/members.js +++ b/core/server/public/members.js @@ -1 +1,44 @@ -MembersThemeBindings.init({ssrUrl: "{{blog-url}}/members/ssr", membersUrl: "{{admin-url}}/api/v2/members/static"}); +const form = document.querySelector('form[data-members-form]'); +if (form) { + form.addEventListener('submit', function (event) { + event.preventDefault(); + form.classList.remove('success', 'invalid', 'error'); + const input = event.target.querySelector('input[data-members-email]'); + const email = input.value; + + if (!email.includes('@')) { + form.classList.add('invalid') + return; + } + + fetch('{{admin-url}}/api/v2/members/send-magic-link/', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + email + }) + }).then(function (res) { + if (res.ok) { + form.classList.add('success') + } else { + form.classList.add('error') + } + }); + }); +} + +const magicLinkRegEx = /token=([a-zA-Z0-9_\-]+\.[a-zA-Z0-9_\-]+\.[a-zA-Z0-9_\-]+)/; +const [isMagicLink, token] = location.search.match(magicLinkRegEx) || [false, null]; + +if (isMagicLink) { + fetch('{{blog-url}}/members/ssr', { + method: 'POST', + body: token + }).then(function (res) { + if (res.ok) { + window.location.search = window.location.search.replace(magicLinkRegEx, ''); + } + }); +} diff --git a/core/server/services/members/api.js b/core/server/services/members/api.js index 69dd00147d..93e00552cb 100644 --- a/core/server/services/members/api.js +++ b/core/server/services/members/api.js @@ -1,34 +1,23 @@ -const url = require('url'); +const {URL} = require('url'); const settingsCache = require('../settings/cache'); const urlUtils = require('../../lib/url-utils'); const MembersApi = require('@tryghost/members-api'); const common = require('../../lib/common'); -const models = require('../../models'); const mail = require('../mail'); -const blogIcon = require('../../lib/image/blog-icon'); -const doBlock = fn => fn(); +const models = require('../../models'); -function createMember({name, email, password}) { +function createMember({email}) { return models.Member.add({ - name, - email, - password - }).then((member) => { - return member.toJSON(); - }); -} - -function updateMember(member, newData) { - return models.Member.findOne(member, { - require: true - }).then(({id}) => { - return models.Member.edit(newData, {id}); + email }).then((member) => { return member.toJSON(); }); } function getMember(data, options = {}) { + if (!data.email && !data.id) { + return Promise.resolve(null); + } return models.Member.findOne(data, options).then((model) => { if (!model) { return null; @@ -57,153 +46,46 @@ function listMembers(options) { }); } -function validateMember({email, password}) { - return models.Member.findOne({email}, { - require: true - }).then((member) => { - return member.comparePassword(password).then((res) => { - if (!res) { - throw new Error('Password is incorrect'); - } - return member; - }); - }).then((member) => { - return member.toJSON(); - }); -} - -function getSubscriptionSettings() { - let membersSettings = settingsCache.get('members_subscription_settings'); - if (!membersSettings) { - membersSettings = { - isPaid: false, - paymentProcessors: [{ - adapter: 'stripe', - config: { - secret_token: '', - public_token: '', - product: { - name: 'Ghost Subscription' - }, - plans: [ - { - name: 'Monthly', - currency: 'usd', - interval: 'month', - amount: '' - }, - { - name: 'Yearly', - currency: 'usd', - interval: 'year', - amount: '' - } - ] - } - }] - }; - } - if (!membersSettings.isPaid) { - membersSettings.paymentProcessors = []; - } - return membersSettings; -} - -const siteUrl = urlUtils.getSiteUrl(); -const siteOrigin = doBlock(() => { - const {protocol, host} = url.parse(siteUrl); - return `${protocol}//${host}`; -}); - -const adminOrigin = doBlock(() => { - const {protocol, host} = url.parse(urlUtils.urlFor('admin', true)); - return `${protocol}//${host}`; -}); - const getApiUrl = ({version, type}) => { - const {href} = new url.URL( + const {href} = new URL( urlUtils.getApiPath({version, type}), urlUtils.urlFor('admin', true) ); return href; }; -const contentApiUrl = getApiUrl({version: 'v2', type: 'content'}); +const siteUrl = urlUtils.getSiteUrl(); const membersApiUrl = getApiUrl({version: 'v2', type: 'members'}); -const accessControl = { - [siteOrigin]: { - [contentApiUrl]: { - tokenLength: '20m' - }, - [membersApiUrl]: { - tokenLength: '180d' - } - }, - '*': { - tokenLength: '20m' - } -}; - -const sendEmail = (function createSendEmail(mailer) { - return function sendEmail(member, {token}) { - if (!(mailer instanceof mail.GhostMailer)) { - mailer = new mail.GhostMailer(); - } - const message = { - to: member.email, - subject: 'Reset password', - html: ` - Hi ${member.name}, - - To reset your password, click the following link and follow the instructions: - - ${siteUrl}#reset-password?token=${token} - - If you didn't request a password change, just ignore this email. - ` - }; - - /* eslint-disable */ - // @TODO remove this - console.log(message.html); - /* eslint-enable */ - return mailer.send(message).catch((err) => { - return Promise.reject(err); - }); - }; -})(); - -const getSiteConfig = () => { - return { - title: settingsCache.get('title') ? settingsCache.get('title').replace(/"/g, '\\"') : 'Publication', - icon: blogIcon.getIconUrl() - }; -}; +const ghostMailer = new mail.GhostMailer(); module.exports = createApiInstance; function createApiInstance() { const membersApiInstance = MembersApi({ - authConfig: { + tokenConfig: { issuer: membersApiUrl, - ssoOrigin: adminOrigin, publicKey: settingsCache.get('members_public_key'), - privateKey: settingsCache.get('members_private_key'), - sessionSecret: settingsCache.get('members_session_secret'), - accessControl + privateKey: settingsCache.get('members_private_key') }, - paymentConfig: { - processors: getSubscriptionSettings().paymentProcessors + auth: { + getSigninURL(token) { + const signinURL = new URL(siteUrl); + signinURL.searchParams.set('token', token); + return signinURL.href; + } + }, + mail: { + transporter: { + sendMail(message) { + return ghostMailer.send(Object.assign({subject: 'Signin'}, message)); + } + } }, - siteConfig: getSiteConfig(), createMember, getMember, deleteMember, - listMembers, - validateMember, - updateMember, - sendEmail + listMembers }); membersApiInstance.setLogger(common.logging); diff --git a/core/server/services/members/index.js b/core/server/services/members/index.js index c81b9d905b..ee37d18bab 100644 --- a/core/server/services/members/index.js +++ b/core/server/services/members/index.js @@ -1,5 +1,3 @@ -const {static} = require('express'); -const path = require('path'); const MembersSSR = require('@tryghost/members-ssr'); const createMembersApiInstance = require('./api'); @@ -47,14 +45,7 @@ const membersService = { // This is passed as a function so that updates to the instance // are picked up in the ssr module membersApi: () => membersApi - }), - - authPages: static( - path.join( - require.resolve('@tryghost/members-auth-pages'), - '../dist' - ) - ) + }) }; module.exports = membersService; diff --git a/core/server/web/api/canary/members/app.js b/core/server/web/api/canary/members/app.js index 84d18d9293..1c1c822063 100644 --- a/core/server/web/api/canary/members/app.js +++ b/core/server/web/api/canary/members/app.js @@ -1,6 +1,9 @@ +const {URL} = require('url'); const debug = require('ghost-ignition').debug('web:canary:members:app'); const express = require('express'); +const cors = require('cors'); const membersService = require('../../../../services/members'); +const urlUtils = require('../../../../lib/url-utils'); const labs = require('../../../shared/middlewares/labs'); const shared = require('../../../shared'); @@ -11,8 +14,9 @@ module.exports = function setupMembersApiApp() { // Entire app is behind labs flag apiApp.use(labs.members); - // Set up the auth pages - apiApp.use('/static/auth', membersService.authPages); + // Support CORS for requests from the frontend + const siteUrl = new URL(urlUtils.getSiteUrl()); + apiApp.use(cors(siteUrl.origin)); // Set up the api endpoints and the gateway // NOTE: this is wrapped in a function to ensure we always go via the getter diff --git a/core/server/web/api/v2/members/app.js b/core/server/web/api/v2/members/app.js index 45a1cfb4ea..32901be2f0 100644 --- a/core/server/web/api/v2/members/app.js +++ b/core/server/web/api/v2/members/app.js @@ -1,6 +1,9 @@ +const {URL} = require('url'); const debug = require('ghost-ignition').debug('web:v2:members:app'); const express = require('express'); +const cors = require('cors'); const membersService = require('../../../../services/members'); +const urlUtils = require('../../../../lib/url-utils'); const labs = require('../../../shared/middlewares/labs'); const shared = require('../../../shared'); @@ -11,8 +14,9 @@ module.exports = function setupMembersApiApp() { // Entire app is behind labs flag apiApp.use(labs.members); - // Set up the auth pages - apiApp.use('/static/auth', membersService.authPages); + // Support CORS for requests from the frontend + const siteUrl = new URL(urlUtils.getSiteUrl()); + apiApp.use(cors(siteUrl.origin)); // Set up the api endpoints and the gateway // NOTE: this is wrapped in a function to ensure we always go via the getter diff --git a/package.json b/package.json index acf8ad1099..32881c330d 100644 --- a/package.json +++ b/package.json @@ -32,8 +32,7 @@ "lint:test": "eslint -c core/test/.eslintrc.json --ignore-path core/test/.eslintignore 'core/test/**/*.js'", "lint": "yarn lint:server && yarn lint:frontend && yarn lint:test", "posttest": "yarn lint", - "fixmodulenotdefined": "yarn cache clean && cd core/client && rm -rf node_modules tmp dist && yarn && cd ../../", - "postinstall": "cpy node_modules/@tryghost/members-theme-bindings/build/members-theme-bindings.js core/server/public/" + "fixmodulenotdefined": "yarn cache clean && cd core/client && rm -rf node_modules tmp dist && yarn && cd ../../" }, "engines": { "node": "^8.10.0 || ^10.13.0", @@ -43,9 +42,7 @@ "@nexes/nql": "0.3.0", "@tryghost/helpers": "1.1.8", "@tryghost/members-api": "0.4.1", - "@tryghost/members-auth-pages": "1.1.0", "@tryghost/members-ssr": "0.3.0", - "@tryghost/members-theme-bindings": "0.2.3", "@tryghost/social-urls": "0.1.2", "@tryghost/string": "^0.1.3", "@tryghost/url-utils": "0.3.0", diff --git a/yarn.lock b/yarn.lock index 343c02d2e6..e0b023bcfb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -210,46 +210,6 @@ node-jose "^1.1.3" stripe "^7.4.0" -"@tryghost/members-auth-pages@1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@tryghost/members-auth-pages/-/members-auth-pages-1.1.0.tgz#417d27d009d90a509debfaf1ffd25ab1cc58aece" - integrity sha512-1+YeHB9JRYj5O48ItcfMz4CLzwrMj5CjAje7Gt+ytXf2+WE2fQeAT2WcWEKS4lBB0ZskDTYjBkGBv+6KQrGG/w== - dependencies: - "@tryghost/members-gateway-protocol" "^0.1.2" - preact "^8.2.1" - preact-compat "^3.17.0" - react-stripe-elements "^2.0.3" - -"@tryghost/members-browser-auth@^0.2.0": - version "0.2.0" - resolved "https://registry.yarnpkg.com/@tryghost/members-browser-auth/-/members-browser-auth-0.2.0.tgz#d2d7ad20d5c5566380851a21aa64b59d9e768860" - integrity sha512-u2G4TdxJctX0ols/kmOqBFFSHVwPAA9sJRf3DQU5DEM0KiMllSvdhADKl2mbaH7rXO+3dNaTUJAc7yXDEu+TaQ== - dependencies: - "@tryghost/members-gateway-api" "^0.1.4" - bluebird "^3.5.4" - ghost-ignition "^3.1.0" - lodash "^4.17.11" - -"@tryghost/members-gateway-api@^0.1.4": - version "0.1.4" - resolved "https://registry.yarnpkg.com/@tryghost/members-gateway-api/-/members-gateway-api-0.1.4.tgz#d458c3ccb574c109861c703a69a4d3e967eb19cc" - integrity sha512-AjrnB6htHy4tR6zvRhokxRkxbGRzMJCOg5fOjc05w2dzolMF2HUeYqIsMtyMn4pnogbJb25WBtkiwxq+s59UWA== - dependencies: - "@tryghost/members-gateway-protocol" "^0.1.2" - bluebird "^3.5.4" - ghost-ignition "^3.1.0" - lodash "^4.17.11" - minivents "^2.2.0" - -"@tryghost/members-gateway-protocol@^0.1.2": - version "0.1.2" - resolved "https://registry.yarnpkg.com/@tryghost/members-gateway-protocol/-/members-gateway-protocol-0.1.2.tgz#afd004bd91b5e403ebb9e130d3208046ce621bc2" - integrity sha512-lZVJ5tKqAiGZhZ+JD+dSjHKN9q04W7JkWPVl/+zOl2FuVbMiIOvlcmrHWug++hZhAyYHcWjnRPM/paRkiR/KBQ== - dependencies: - bluebird "^3.5.4" - ghost-ignition "^3.1.0" - lodash "^4.17.11" - "@tryghost/members-ssr@0.3.0": version "0.3.0" resolved "https://registry.yarnpkg.com/@tryghost/members-ssr/-/members-ssr-0.3.0.tgz#92e972a35c4eb571c25678f6864c183a0dc2a8df" @@ -262,16 +222,6 @@ jsonwebtoken "^8.5.1" lodash "^4.17.11" -"@tryghost/members-theme-bindings@0.2.3": - version "0.2.3" - resolved "https://registry.yarnpkg.com/@tryghost/members-theme-bindings/-/members-theme-bindings-0.2.3.tgz#0f69ec555425a12a8e1436331c62408677354c2d" - integrity sha512-uFtAZvKSWJMlNeUv0U+jKQBfCJpXxewP5g+VPAZJPeY52JMM6uLfJIyhUtWWulvhyV+bJC3X9hb5vVHfkTARXQ== - dependencies: - "@tryghost/members-browser-auth" "^0.2.0" - bluebird "^3.5.4" - ghost-ignition "^3.1.0" - lodash "^4.17.11" - "@tryghost/mobiledoc-kit@^0.11.2-ghost.4": version "0.11.2-ghost.4" resolved "https://registry.yarnpkg.com/@tryghost/mobiledoc-kit/-/mobiledoc-kit-0.11.2-ghost.4.tgz#144189e7e62748b3c56e7b723fa18a5e8c807ccf" @@ -4023,13 +3973,6 @@ image-size@0.7.4, image-size@^0.7.4: resolved "https://registry.yarnpkg.com/image-size/-/image-size-0.7.4.tgz#092c1e541a93511917bfc957a1fc7add21c72e87" integrity sha512-GqPgxs+VkOr12aWwjSkyRzf5atzObWpFtiRuDgxCl2I/SDpZOKZFRD3iIAeAN6/usmn8SeLWRt7a8JRYK0Whbw== -immutability-helper@^2.7.1: - version "2.9.1" - resolved "https://registry.yarnpkg.com/immutability-helper/-/immutability-helper-2.9.1.tgz#71c423ba387e67b6c6ceba0650572f2a2a6727df" - integrity sha512-r/RmRG8xO06s/k+PIaif2r5rGc3j4Yhc01jSBfwPCXDLYZwp/yxralI37Df1mwmuzcCsen/E/ITKcTEvc1PQmQ== - dependencies: - invariant "^2.2.0" - import-fresh@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.1.0.tgz#6d33fa1dcef6df930fae003446f33415af905118" @@ -4184,13 +4127,6 @@ intl@1.2.5: resolved "https://registry.yarnpkg.com/intl/-/intl-1.2.5.tgz#82244a2190c4e419f8371f5aa34daa3420e2abde" integrity sha1-giRKIZDE5Bn4Nx9ao02qNCDiq94= -invariant@^2.2.0: - version "2.2.4" - resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" - integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA== - dependencies: - loose-envify "^1.0.0" - invert-kv@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6" @@ -4546,16 +4482,16 @@ js-beautify@1.8.8: mkdirp "~0.5.0" nopt "~4.0.1" -"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" - integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== - js-tokens@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" integrity sha1-mGbfOVECEw449/mWvOtlRDIJwls= +js-tokens@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" + integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== + js-yaml@3.13.1, js-yaml@^3.13.0, js-yaml@^3.13.1, js-yaml@^3.9.1, js-yaml@~3.13.0: version "3.13.1" resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.13.1.tgz#aff151b30bfdfa8e49e05da22e7415e9dfa37847" @@ -5135,13 +5071,6 @@ long@^4.0.0: resolved "https://registry.yarnpkg.com/long/-/long-4.0.0.tgz#9a7b71cfb7d361a194ea555241c92f7468d5bf28" integrity sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA== -loose-envify@^1.0.0, loose-envify@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" - integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== - dependencies: - js-tokens "^3.0.0 || ^4.0.0" - loud-rejection@^1.0.0: version "1.6.0" resolved "https://registry.yarnpkg.com/loud-rejection/-/loud-rejection-1.6.0.tgz#5b46f80147edee578870f086d04821cf998e551f" @@ -5571,11 +5500,6 @@ minipass@^2.2.1, minipass@^2.3.5: safe-buffer "^5.1.2" yallist "^3.0.0" -minivents@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/minivents/-/minivents-2.2.0.tgz#559492edc04bc00b62168850af5b8ca06d5e088b" - integrity sha1-VZSS7cBLwAtiFohQr1uMoG1eCIs= - minizlib@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.2.1.tgz#dd27ea6136243c7c880684e8672bb3a45fd9b614" @@ -6855,40 +6779,6 @@ posthtml@^0.9.0: posthtml-parser "^0.2.0" posthtml-render "^1.0.5" -preact-compat@^3.17.0: - version "3.19.0" - resolved "https://registry.yarnpkg.com/preact-compat/-/preact-compat-3.19.0.tgz#a71457b6a3bf051690a4411603bc2085aa061c2f" - integrity sha512-f83A4hIhH8Uzhb9GbIcGk8SM19ffWlwP9mDaYwQdRnMdekZwcCA7eIAbeV4EMQaV9C0Yuy8iKgBAtyTKPZQt/Q== - dependencies: - immutability-helper "^2.7.1" - preact-context "^1.1.3" - preact-render-to-string "^3.8.2" - preact-transition-group "^1.1.1" - prop-types "^15.6.2" - standalone-react-addons-pure-render-mixin "^0.1.1" - -preact-context@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/preact-context/-/preact-context-1.1.3.tgz#26d06db0f39d8d9c890df5ada9a99a943586ec68" - integrity sha512-2LcpjZG6JUhBgqziVH+nJtmu9PS5KzWoFx6wX2svXw0oBHhU6e8tQZhEkKLMOAxdmj7gVzApfS/B6V+fjJ/llA== - -preact-render-to-string@^3.8.2: - version "3.8.2" - resolved "https://registry.yarnpkg.com/preact-render-to-string/-/preact-render-to-string-3.8.2.tgz#bd72964d705a57da3a9e72098acaa073dd3ceff9" - integrity sha512-przuZPajiurStGgxMoJP0EJeC4xj5CgHv+M7GfF3YxAdhGgEWAkhOSE0xympAFN20uMayntBZpttIZqqLl77fw== - dependencies: - pretty-format "^3.5.1" - -preact-transition-group@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/preact-transition-group/-/preact-transition-group-1.1.1.tgz#f0a49327ea515ece34ea2be864c4a7d29e5d6e10" - integrity sha1-8KSTJ+pRXs406ivoZMSn0p5dbhA= - -preact@^8.2.1: - version "8.4.2" - resolved "https://registry.yarnpkg.com/preact/-/preact-8.4.2.tgz#1263b974a17d1ea80b66590e41ef786ced5d6a23" - integrity sha512-TsINETWiisfB6RTk0wh3/mvxbGRvx+ljeBccZ4Z6MPFKgu/KFGyf2Bmw3Z/jlXhL5JlNKY6QAbA9PVyzIy9//A== - prebuild-install@^2.3.0: version "2.5.3" resolved "https://registry.yarnpkg.com/prebuild-install/-/prebuild-install-2.5.3.tgz#9f65f242782d370296353710e9bc843490c19f69" @@ -6959,11 +6849,6 @@ pretty-bytes@^4.0.2: resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-4.0.2.tgz#b2bf82e7350d65c6c33aa95aaa5a4f6327f61cd9" integrity sha1-sr+C5zUNZcbDOqlaqlpPYyf2HNk= -pretty-format@^3.5.1: - version "3.8.0" - resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-3.8.0.tgz#bfbed56d5e9a776645f4b1ff7aa1a3ac4fa3c385" - integrity sha1-v77VbV6ad2ZF9LH/eqGjrE+jw4U= - prettyjson@^1.1.3: version "1.2.1" resolved "https://registry.yarnpkg.com/prettyjson/-/prettyjson-1.2.1.tgz#fcffab41d19cab4dfae5e575e64246619b12d289" @@ -6999,15 +6884,6 @@ promise-wtf@^1.2.4: resolved "https://registry.yarnpkg.com/promise-wtf/-/promise-wtf-1.2.4.tgz#8cbdd31ea10dee074fbb6387cbc96e413993376c" integrity sha512-wOZ+ZUG0/Lsk+muOElLtteIteyvF5B1bNcVLhmlv6PDKcAAQGa5Bf0maN3rj73FWyjJE840MzeQyNE6KOKpgrg== -prop-types@^15.5.10, prop-types@^15.6.2: - version "15.7.2" - resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5" - integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ== - dependencies: - loose-envify "^1.4.0" - object-assign "^4.1.1" - react-is "^16.8.1" - propagate@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/propagate/-/propagate-1.0.0.tgz#00c2daeedda20e87e3782b344adba1cddd6ad709" @@ -7170,18 +7046,6 @@ rc@^1.1.6, rc@^1.2.7: minimist "^1.2.0" strip-json-comments "~2.0.1" -react-is@^16.8.1: - version "16.8.6" - resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.8.6.tgz#5bbc1e2d29141c9fbdfed456343fe2bc430a6a16" - integrity sha512-aUk3bHfZ2bRSVFFbbeVS4i+lNPZr3/WM5jT2J5omUVV1zzcs1nAaf3l51ctA5FFvCRbhrH0bdAsRRQddFJZPtA== - -react-stripe-elements@^2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/react-stripe-elements/-/react-stripe-elements-2.0.3.tgz#cfd0f68d00ce52a07aab1cb2b59b29dc12309486" - integrity sha512-aKLiWyfP0n3Gq42BKykULgoruNVRXEaeYh8NSokdgH3ubGU3nsHFZJg3LgbT/XOquttDGHE7kLhleaX+UnN81A== - dependencies: - prop-types "^15.5.10" - read-pkg-up@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02" @@ -8037,11 +7901,6 @@ stack-trace@0.0.10: resolved "https://registry.yarnpkg.com/stack-trace/-/stack-trace-0.0.10.tgz#547c70b347e8d32b4e108ea1a2a159e5fdde19c0" integrity sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA= -standalone-react-addons-pure-render-mixin@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/standalone-react-addons-pure-render-mixin/-/standalone-react-addons-pure-render-mixin-0.1.1.tgz#3c7409f4c79c40de9ac72c616cf679a994f37551" - integrity sha1-PHQJ9MecQN6axyxhbPZ5qZTzdVE= - static-eval@2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/static-eval/-/static-eval-2.0.2.tgz#2d1759306b1befa688938454c546b7871f806a42"