From dbf395aaf12257db437f9389a3ad143b17171d7a Mon Sep 17 00:00:00 2001 From: Igor Karpilenko Date: Fri, 24 Jul 2020 13:37:20 +0300 Subject: [PATCH 1/9] Add patch for video_embed_field --- README.md | 4 +++- ...deo_embed_field_vimeo_private_videos.patch | 22 +++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) create mode 100644 patches/video_embed_field_vimeo_private_videos.patch diff --git a/README.md b/README.md index e6e449fb3..438f2235d 100644 --- a/README.md +++ b/README.md @@ -56,7 +56,9 @@ For videos, protected from embed by "Specific domains" you can have an issue with thumbnails download to drupal media. In this case - apply a patch for drupal core: -* _patches/OEmbed\_vimeo\_private\_videos.patch_ +* _patches/OEmbed\_vimeo\_private\_videos.patch_ - in case of using core media +* _patches/video\_embed\_field\_vimeo\_private\_videos.patch_ - in case of +using video_embed_field module ### JSON API patch required for Drupal 8.7 diff --git a/patches/video_embed_field_vimeo_private_videos.patch b/patches/video_embed_field_vimeo_private_videos.patch new file mode 100644 index 000000000..7f28f7be9 --- /dev/null +++ b/patches/video_embed_field_vimeo_private_videos.patch @@ -0,0 +1,22 @@ +Index: a/src/Plugin/video_embed_field/Provider/Vimeo.php +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- a/src/Plugin/video_embed_field/Provider/Vimeo.php (date 1595585152357) ++++ b/src/Plugin/video_embed_field/Provider/Vimeo.php (date 1595585152357) +@@ -52,7 +52,13 @@ + * An array of data from the oembed endpoint. + */ + protected function oEmbedData() { +- return json_decode(file_get_contents('http://vimeo.com/api/oembed.json?url=' . $this->getInput())); ++ $opts = [ ++ 'http' => [ ++ 'header' => ["Referer: " . $_SERVER['HTTP_REFERER']] ++ ], ++ ]; ++ $context = stream_context_create($opts); ++ return json_decode(file_get_contents('http://vimeo.com/api/oembed.json?url=' . $this->getInput(), FALSE, $context)); + } + + /** From dff758d1902cd25d9e1c4fbca25a047dcd8a2e8f Mon Sep 17 00:00:00 2001 From: Igor Karpilenko Date: Fri, 24 Jul 2020 18:00:02 +0300 Subject: [PATCH 2/9] [VYMCA-64] CSV Security Enhancement --- .../dist/gated-content.umd.min.js | 4208 +---------------- .../src/components/auth/CustomAuth.vue | 42 +- .../auth/CustomAuthEmailConfirm.vue | 68 + js/gated-content/src/router/index.js | 8 + .../src/store/modules/auth/custom.js | 32 + js/gated-content/src/views/Login.vue | 2 - .../install/openy_gc_auth.provider.custom.yml | 7 +- ....resource.openy_gc_auth_custom_confirm.yml | 17 + .../openy_gc_auth_custom.info.yml | 1 + .../openy_gc_auth_custom.install | 43 + .../openy_gc_auth_custom.module | 16 + .../src/Entity/AuthCustomUser.php | 62 + .../src/Plugin/GCIdentityProvider/Custom.php | 68 +- .../src/Plugin/rest/ErrorResponseTrait.php | 30 + .../GatedContentCustomAuthConfirm.php | 142 + .../GatedContentCustomAuthentication.php | 107 +- ...igration.virtual_y_gc_auth_custom_user.yml | 66 + 17 files changed, 684 insertions(+), 4235 deletions(-) create mode 100644 js/gated-content/src/components/auth/CustomAuthEmailConfirm.vue create mode 100644 modules/openy_gc_auth/modules/openy_gc_auth_custom/config/install/rest.resource.openy_gc_auth_custom_confirm.yml create mode 100644 modules/openy_gc_auth/modules/openy_gc_auth_custom/src/Plugin/rest/ErrorResponseTrait.php create mode 100644 modules/openy_gc_auth/modules/openy_gc_auth_custom/src/Plugin/rest/resource/GatedContentCustomAuthConfirm.php create mode 100644 modules/openy_gc_demo/migrations/migrate_plus.migration.virtual_y_gc_auth_custom_user.yml diff --git a/js/gated-content/dist/gated-content.umd.min.js b/js/gated-content/dist/gated-content.umd.min.js index 2952ac022..29d4078e9 100644 --- a/js/gated-content/dist/gated-content.umd.min.js +++ b/js/gated-content/dist/gated-content.umd.min.js @@ -1,4190 +1,18 @@ -(function webpackUniversalModuleDefinition(root, factory) { - if(typeof exports === 'object' && typeof module === 'object') - module.exports = factory(require("axios"), require("vue"), require("VueRecaptcha"), require("VueRouter"), require("Vuex"), require("VuexPersistence")); - else if(typeof define === 'function' && define.amd) - define(["axios", , "VueRecaptcha", "VueRouter", "Vuex", "VuexPersistence"], factory); - else if(typeof exports === 'object') - exports["gated-content"] = factory(require("axios"), require("vue"), require("VueRecaptcha"), require("VueRouter"), require("Vuex"), require("VuexPersistence")); - else - root["gated-content"] = factory(root["axios"], root["Vue"], root["VueRecaptcha"], root["VueRouter"], root["Vuex"], root["VuexPersistence"]); -})((typeof self !== 'undefined' ? self : this), function(__WEBPACK_EXTERNAL_MODULE_axios__, __WEBPACK_EXTERNAL_MODULE_vue__, __WEBPACK_EXTERNAL_MODULE_vue_recaptcha__, __WEBPACK_EXTERNAL_MODULE_vue_router__, __WEBPACK_EXTERNAL_MODULE_vuex__, __WEBPACK_EXTERNAL_MODULE_vuex_persist__) { -return /******/ (function(modules) { // webpackBootstrap -/******/ // The module cache -/******/ var installedModules = {}; -/******/ -/******/ // The require function -/******/ function __webpack_require__(moduleId) { -/******/ -/******/ // Check if module is in cache -/******/ if(installedModules[moduleId]) { -/******/ return installedModules[moduleId].exports; -/******/ } -/******/ // Create a new module (and put it into the cache) -/******/ var module = installedModules[moduleId] = { -/******/ i: moduleId, -/******/ l: false, -/******/ exports: {} -/******/ }; -/******/ -/******/ // Execute the module function -/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); -/******/ -/******/ // Flag the module as loaded -/******/ module.l = true; -/******/ -/******/ // Return the exports of the module -/******/ return module.exports; -/******/ } -/******/ -/******/ -/******/ // expose the modules object (__webpack_modules__) -/******/ __webpack_require__.m = modules; -/******/ -/******/ // expose the module cache -/******/ __webpack_require__.c = installedModules; -/******/ -/******/ // define getter function for harmony exports -/******/ __webpack_require__.d = function(exports, name, getter) { -/******/ if(!__webpack_require__.o(exports, name)) { -/******/ Object.defineProperty(exports, name, { enumerable: true, get: getter }); -/******/ } -/******/ }; -/******/ -/******/ // define __esModule on exports -/******/ __webpack_require__.r = function(exports) { -/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { -/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); -/******/ } -/******/ Object.defineProperty(exports, '__esModule', { value: true }); -/******/ }; -/******/ -/******/ // create a fake namespace object -/******/ // mode & 1: value is a module id, require it -/******/ // mode & 2: merge all properties of value into the ns -/******/ // mode & 4: return value when already ns object -/******/ // mode & 8|1: behave like require -/******/ __webpack_require__.t = function(value, mode) { -/******/ if(mode & 1) value = __webpack_require__(value); -/******/ if(mode & 8) return value; -/******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value; -/******/ var ns = Object.create(null); -/******/ __webpack_require__.r(ns); -/******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value }); -/******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key)); -/******/ return ns; -/******/ }; -/******/ -/******/ // getDefaultExport function for compatibility with non-harmony modules -/******/ __webpack_require__.n = function(module) { -/******/ var getter = module && module.__esModule ? -/******/ function getDefault() { return module['default']; } : -/******/ function getModuleExports() { return module; }; -/******/ __webpack_require__.d(getter, 'a', getter); -/******/ return getter; -/******/ }; -/******/ -/******/ // Object.prototype.hasOwnProperty.call -/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; -/******/ -/******/ // __webpack_public_path__ -/******/ __webpack_require__.p = ""; -/******/ -/******/ -/******/ // Load entry module and return exports -/******/ return __webpack_require__(__webpack_require__.s = "./node_modules/@vue/cli-service/lib/commands/build/entry-lib-no-default.js"); -/******/ }) -/************************************************************************/ -/******/ ({ - -/***/ "./node_modules/@babel/runtime/helpers/esm/arrayLikeToArray.js": -/*!*********************************************************************!*\ - !*** ./node_modules/@babel/runtime/helpers/esm/arrayLikeToArray.js ***! - \*********************************************************************/ -/*! exports provided: default */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"default\", function() { return _arrayLikeToArray; });\nfunction _arrayLikeToArray(arr, len) {\n if (len == null || len > arr.length) len = arr.length;\n\n for (var i = 0, arr2 = new Array(len); i < len; i++) {\n arr2[i] = arr[i];\n }\n\n return arr2;\n}\n\n//# sourceURL=webpack://gated-content/./node_modules/@babel/runtime/helpers/esm/arrayLikeToArray.js?"); - -/***/ }), - -/***/ "./node_modules/@babel/runtime/helpers/esm/arrayWithoutHoles.js": -/*!**********************************************************************!*\ - !*** ./node_modules/@babel/runtime/helpers/esm/arrayWithoutHoles.js ***! - \**********************************************************************/ -/*! exports provided: default */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"default\", function() { return _arrayWithoutHoles; });\n/* harmony import */ var _arrayLikeToArray__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./arrayLikeToArray */ \"./node_modules/@babel/runtime/helpers/esm/arrayLikeToArray.js\");\n\nfunction _arrayWithoutHoles(arr) {\n if (Array.isArray(arr)) return Object(_arrayLikeToArray__WEBPACK_IMPORTED_MODULE_0__[\"default\"])(arr);\n}\n\n//# sourceURL=webpack://gated-content/./node_modules/@babel/runtime/helpers/esm/arrayWithoutHoles.js?"); - -/***/ }), - -/***/ "./node_modules/@babel/runtime/helpers/esm/asyncToGenerator.js": -/*!*********************************************************************!*\ - !*** ./node_modules/@babel/runtime/helpers/esm/asyncToGenerator.js ***! - \*********************************************************************/ -/*! exports provided: default */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"default\", function() { return _asyncToGenerator; });\n/* harmony import */ var core_js_modules_es_object_to_string__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! core-js/modules/es.object.to-string */ \"./node_modules/core-js/modules/es.object.to-string.js\");\n/* harmony import */ var core_js_modules_es_object_to_string__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(core_js_modules_es_object_to_string__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var core_js_modules_es_promise__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! core-js/modules/es.promise */ \"./node_modules/core-js/modules/es.promise.js\");\n/* harmony import */ var core_js_modules_es_promise__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(core_js_modules_es_promise__WEBPACK_IMPORTED_MODULE_1__);\n\n\n\nfunction asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {\n try {\n var info = gen[key](arg);\n var value = info.value;\n } catch (error) {\n reject(error);\n return;\n }\n\n if (info.done) {\n resolve(value);\n } else {\n Promise.resolve(value).then(_next, _throw);\n }\n}\n\nfunction _asyncToGenerator(fn) {\n return function () {\n var self = this,\n args = arguments;\n return new Promise(function (resolve, reject) {\n var gen = fn.apply(self, args);\n\n function _next(value) {\n asyncGeneratorStep(gen, resolve, reject, _next, _throw, \"next\", value);\n }\n\n function _throw(err) {\n asyncGeneratorStep(gen, resolve, reject, _next, _throw, \"throw\", err);\n }\n\n _next(undefined);\n });\n };\n}\n\n//# sourceURL=webpack://gated-content/./node_modules/@babel/runtime/helpers/esm/asyncToGenerator.js?"); - -/***/ }), - -/***/ "./node_modules/@babel/runtime/helpers/esm/defineProperty.js": -/*!*******************************************************************!*\ - !*** ./node_modules/@babel/runtime/helpers/esm/defineProperty.js ***! - \*******************************************************************/ -/*! exports provided: default */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"default\", function() { return _defineProperty; });\nfunction _defineProperty(obj, key, value) {\n if (key in obj) {\n Object.defineProperty(obj, key, {\n value: value,\n enumerable: true,\n configurable: true,\n writable: true\n });\n } else {\n obj[key] = value;\n }\n\n return obj;\n}\n\n//# sourceURL=webpack://gated-content/./node_modules/@babel/runtime/helpers/esm/defineProperty.js?"); - -/***/ }), - -/***/ "./node_modules/@babel/runtime/helpers/esm/iterableToArray.js": -/*!********************************************************************!*\ - !*** ./node_modules/@babel/runtime/helpers/esm/iterableToArray.js ***! - \********************************************************************/ -/*! exports provided: default */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"default\", function() { return _iterableToArray; });\n/* harmony import */ var core_js_modules_es_symbol__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! core-js/modules/es.symbol */ \"./node_modules/core-js/modules/es.symbol.js\");\n/* harmony import */ var core_js_modules_es_symbol__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(core_js_modules_es_symbol__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var core_js_modules_es_symbol_description__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! core-js/modules/es.symbol.description */ \"./node_modules/core-js/modules/es.symbol.description.js\");\n/* harmony import */ var core_js_modules_es_symbol_description__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(core_js_modules_es_symbol_description__WEBPACK_IMPORTED_MODULE_1__);\n/* harmony import */ var core_js_modules_es_symbol_iterator__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! core-js/modules/es.symbol.iterator */ \"./node_modules/core-js/modules/es.symbol.iterator.js\");\n/* harmony import */ var core_js_modules_es_symbol_iterator__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(core_js_modules_es_symbol_iterator__WEBPACK_IMPORTED_MODULE_2__);\n/* harmony import */ var core_js_modules_es_array_from__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! core-js/modules/es.array.from */ \"./node_modules/core-js/modules/es.array.from.js\");\n/* harmony import */ var core_js_modules_es_array_from__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(core_js_modules_es_array_from__WEBPACK_IMPORTED_MODULE_3__);\n/* harmony import */ var core_js_modules_es_array_iterator__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! core-js/modules/es.array.iterator */ \"./node_modules/core-js/modules/es.array.iterator.js\");\n/* harmony import */ var core_js_modules_es_array_iterator__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__webpack_require__.n(core_js_modules_es_array_iterator__WEBPACK_IMPORTED_MODULE_4__);\n/* harmony import */ var core_js_modules_es_object_to_string__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! core-js/modules/es.object.to-string */ \"./node_modules/core-js/modules/es.object.to-string.js\");\n/* harmony import */ var core_js_modules_es_object_to_string__WEBPACK_IMPORTED_MODULE_5___default = /*#__PURE__*/__webpack_require__.n(core_js_modules_es_object_to_string__WEBPACK_IMPORTED_MODULE_5__);\n/* harmony import */ var core_js_modules_es_string_iterator__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! core-js/modules/es.string.iterator */ \"./node_modules/core-js/modules/es.string.iterator.js\");\n/* harmony import */ var core_js_modules_es_string_iterator__WEBPACK_IMPORTED_MODULE_6___default = /*#__PURE__*/__webpack_require__.n(core_js_modules_es_string_iterator__WEBPACK_IMPORTED_MODULE_6__);\n/* harmony import */ var core_js_modules_web_dom_collections_iterator__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! core-js/modules/web.dom-collections.iterator */ \"./node_modules/core-js/modules/web.dom-collections.iterator.js\");\n/* harmony import */ var core_js_modules_web_dom_collections_iterator__WEBPACK_IMPORTED_MODULE_7___default = /*#__PURE__*/__webpack_require__.n(core_js_modules_web_dom_collections_iterator__WEBPACK_IMPORTED_MODULE_7__);\n\n\n\n\n\n\n\n\nfunction _iterableToArray(iter) {\n if (typeof Symbol !== \"undefined\" && Symbol.iterator in Object(iter)) return Array.from(iter);\n}\n\n//# sourceURL=webpack://gated-content/./node_modules/@babel/runtime/helpers/esm/iterableToArray.js?"); - -/***/ }), - -/***/ "./node_modules/@babel/runtime/helpers/esm/nonIterableSpread.js": -/*!**********************************************************************!*\ - !*** ./node_modules/@babel/runtime/helpers/esm/nonIterableSpread.js ***! - \**********************************************************************/ -/*! exports provided: default */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"default\", function() { return _nonIterableSpread; });\nfunction _nonIterableSpread() {\n throw new TypeError(\"Invalid attempt to spread non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.\");\n}\n\n//# sourceURL=webpack://gated-content/./node_modules/@babel/runtime/helpers/esm/nonIterableSpread.js?"); - -/***/ }), - -/***/ "./node_modules/@babel/runtime/helpers/esm/objectSpread2.js": -/*!******************************************************************!*\ - !*** ./node_modules/@babel/runtime/helpers/esm/objectSpread2.js ***! - \******************************************************************/ -/*! exports provided: default */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"default\", function() { return _objectSpread2; });\n/* harmony import */ var core_js_modules_es_symbol__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! core-js/modules/es.symbol */ \"./node_modules/core-js/modules/es.symbol.js\");\n/* harmony import */ var core_js_modules_es_symbol__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(core_js_modules_es_symbol__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var core_js_modules_es_array_filter__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! core-js/modules/es.array.filter */ \"./node_modules/core-js/modules/es.array.filter.js\");\n/* harmony import */ var core_js_modules_es_array_filter__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(core_js_modules_es_array_filter__WEBPACK_IMPORTED_MODULE_1__);\n/* harmony import */ var core_js_modules_es_array_for_each__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! core-js/modules/es.array.for-each */ \"./node_modules/core-js/modules/es.array.for-each.js\");\n/* harmony import */ var core_js_modules_es_array_for_each__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(core_js_modules_es_array_for_each__WEBPACK_IMPORTED_MODULE_2__);\n/* harmony import */ var core_js_modules_es_object_get_own_property_descriptor__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! core-js/modules/es.object.get-own-property-descriptor */ \"./node_modules/core-js/modules/es.object.get-own-property-descriptor.js\");\n/* harmony import */ var core_js_modules_es_object_get_own_property_descriptor__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(core_js_modules_es_object_get_own_property_descriptor__WEBPACK_IMPORTED_MODULE_3__);\n/* harmony import */ var core_js_modules_es_object_get_own_property_descriptors__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! core-js/modules/es.object.get-own-property-descriptors */ \"./node_modules/core-js/modules/es.object.get-own-property-descriptors.js\");\n/* harmony import */ var core_js_modules_es_object_get_own_property_descriptors__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__webpack_require__.n(core_js_modules_es_object_get_own_property_descriptors__WEBPACK_IMPORTED_MODULE_4__);\n/* harmony import */ var core_js_modules_es_object_keys__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! core-js/modules/es.object.keys */ \"./node_modules/core-js/modules/es.object.keys.js\");\n/* harmony import */ var core_js_modules_es_object_keys__WEBPACK_IMPORTED_MODULE_5___default = /*#__PURE__*/__webpack_require__.n(core_js_modules_es_object_keys__WEBPACK_IMPORTED_MODULE_5__);\n/* harmony import */ var core_js_modules_web_dom_collections_for_each__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! core-js/modules/web.dom-collections.for-each */ \"./node_modules/core-js/modules/web.dom-collections.for-each.js\");\n/* harmony import */ var core_js_modules_web_dom_collections_for_each__WEBPACK_IMPORTED_MODULE_6___default = /*#__PURE__*/__webpack_require__.n(core_js_modules_web_dom_collections_for_each__WEBPACK_IMPORTED_MODULE_6__);\n/* harmony import */ var _defineProperty__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./defineProperty */ \"./node_modules/@babel/runtime/helpers/esm/defineProperty.js\");\n\n\n\n\n\n\n\n\n\nfunction ownKeys(object, enumerableOnly) {\n var keys = Object.keys(object);\n\n if (Object.getOwnPropertySymbols) {\n var symbols = Object.getOwnPropertySymbols(object);\n if (enumerableOnly) symbols = symbols.filter(function (sym) {\n return Object.getOwnPropertyDescriptor(object, sym).enumerable;\n });\n keys.push.apply(keys, symbols);\n }\n\n return keys;\n}\n\nfunction _objectSpread2(target) {\n for (var i = 1; i < arguments.length; i++) {\n var source = arguments[i] != null ? arguments[i] : {};\n\n if (i % 2) {\n ownKeys(Object(source), true).forEach(function (key) {\n Object(_defineProperty__WEBPACK_IMPORTED_MODULE_7__[\"default\"])(target, key, source[key]);\n });\n } else if (Object.getOwnPropertyDescriptors) {\n Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));\n } else {\n ownKeys(Object(source)).forEach(function (key) {\n Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));\n });\n }\n }\n\n return target;\n}\n\n//# sourceURL=webpack://gated-content/./node_modules/@babel/runtime/helpers/esm/objectSpread2.js?"); - -/***/ }), - -/***/ "./node_modules/@babel/runtime/helpers/esm/toConsumableArray.js": -/*!**********************************************************************!*\ - !*** ./node_modules/@babel/runtime/helpers/esm/toConsumableArray.js ***! - \**********************************************************************/ -/*! exports provided: default */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"default\", function() { return _toConsumableArray; });\n/* harmony import */ var _arrayWithoutHoles__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./arrayWithoutHoles */ \"./node_modules/@babel/runtime/helpers/esm/arrayWithoutHoles.js\");\n/* harmony import */ var _iterableToArray__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./iterableToArray */ \"./node_modules/@babel/runtime/helpers/esm/iterableToArray.js\");\n/* harmony import */ var _unsupportedIterableToArray__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./unsupportedIterableToArray */ \"./node_modules/@babel/runtime/helpers/esm/unsupportedIterableToArray.js\");\n/* harmony import */ var _nonIterableSpread__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./nonIterableSpread */ \"./node_modules/@babel/runtime/helpers/esm/nonIterableSpread.js\");\n\n\n\n\nfunction _toConsumableArray(arr) {\n return Object(_arrayWithoutHoles__WEBPACK_IMPORTED_MODULE_0__[\"default\"])(arr) || Object(_iterableToArray__WEBPACK_IMPORTED_MODULE_1__[\"default\"])(arr) || Object(_unsupportedIterableToArray__WEBPACK_IMPORTED_MODULE_2__[\"default\"])(arr) || Object(_nonIterableSpread__WEBPACK_IMPORTED_MODULE_3__[\"default\"])();\n}\n\n//# sourceURL=webpack://gated-content/./node_modules/@babel/runtime/helpers/esm/toConsumableArray.js?"); - -/***/ }), - -/***/ "./node_modules/@babel/runtime/helpers/esm/unsupportedIterableToArray.js": -/*!*******************************************************************************!*\ - !*** ./node_modules/@babel/runtime/helpers/esm/unsupportedIterableToArray.js ***! - \*******************************************************************************/ -/*! exports provided: default */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"default\", function() { return _unsupportedIterableToArray; });\n/* harmony import */ var core_js_modules_es_array_from__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! core-js/modules/es.array.from */ \"./node_modules/core-js/modules/es.array.from.js\");\n/* harmony import */ var core_js_modules_es_array_from__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(core_js_modules_es_array_from__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var core_js_modules_es_array_slice__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! core-js/modules/es.array.slice */ \"./node_modules/core-js/modules/es.array.slice.js\");\n/* harmony import */ var core_js_modules_es_array_slice__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(core_js_modules_es_array_slice__WEBPACK_IMPORTED_MODULE_1__);\n/* harmony import */ var core_js_modules_es_function_name__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! core-js/modules/es.function.name */ \"./node_modules/core-js/modules/es.function.name.js\");\n/* harmony import */ var core_js_modules_es_function_name__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(core_js_modules_es_function_name__WEBPACK_IMPORTED_MODULE_2__);\n/* harmony import */ var core_js_modules_es_object_to_string__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! core-js/modules/es.object.to-string */ \"./node_modules/core-js/modules/es.object.to-string.js\");\n/* harmony import */ var core_js_modules_es_object_to_string__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(core_js_modules_es_object_to_string__WEBPACK_IMPORTED_MODULE_3__);\n/* harmony import */ var core_js_modules_es_regexp_to_string__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! core-js/modules/es.regexp.to-string */ \"./node_modules/core-js/modules/es.regexp.to-string.js\");\n/* harmony import */ var core_js_modules_es_regexp_to_string__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__webpack_require__.n(core_js_modules_es_regexp_to_string__WEBPACK_IMPORTED_MODULE_4__);\n/* harmony import */ var core_js_modules_es_string_iterator__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! core-js/modules/es.string.iterator */ \"./node_modules/core-js/modules/es.string.iterator.js\");\n/* harmony import */ var core_js_modules_es_string_iterator__WEBPACK_IMPORTED_MODULE_5___default = /*#__PURE__*/__webpack_require__.n(core_js_modules_es_string_iterator__WEBPACK_IMPORTED_MODULE_5__);\n/* harmony import */ var _arrayLikeToArray__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./arrayLikeToArray */ \"./node_modules/@babel/runtime/helpers/esm/arrayLikeToArray.js\");\n\n\n\n\n\n\n\nfunction _unsupportedIterableToArray(o, minLen) {\n if (!o) return;\n if (typeof o === \"string\") return Object(_arrayLikeToArray__WEBPACK_IMPORTED_MODULE_6__[\"default\"])(o, minLen);\n var n = Object.prototype.toString.call(o).slice(8, -1);\n if (n === \"Object\" && o.constructor) n = o.constructor.name;\n if (n === \"Map\" || n === \"Set\") return Array.from(o);\n if (n === \"Arguments\" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return Object(_arrayLikeToArray__WEBPACK_IMPORTED_MODULE_6__[\"default\"])(o, minLen);\n}\n\n//# sourceURL=webpack://gated-content/./node_modules/@babel/runtime/helpers/esm/unsupportedIterableToArray.js?"); - -/***/ }), - -/***/ "./node_modules/@soda/get-current-script/index.js": -/*!********************************************************!*\ - !*** ./node_modules/@soda/get-current-script/index.js ***! - \********************************************************/ -/*! no static exports found */ -/***/ (function(module, exports, __webpack_require__) { - -eval("var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;// addapted from the document.currentScript polyfill by Adam Miller\n// MIT license\n// source: https://github.com/amiller-gh/currentScript-polyfill\n\n// added support for Firefox https://bugzilla.mozilla.org/show_bug.cgi?id=1620505\n\n(function (root, factory) {\n if (true) {\n !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_FACTORY__ = (factory),\n\t\t\t\t__WEBPACK_AMD_DEFINE_RESULT__ = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ?\n\t\t\t\t(__WEBPACK_AMD_DEFINE_FACTORY__.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__)) : __WEBPACK_AMD_DEFINE_FACTORY__),\n\t\t\t\t__WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));\n } else {}\n}(typeof self !== 'undefined' ? self : this, function () {\n function getCurrentScript () {\n if (document.currentScript) {\n return document.currentScript\n }\n \n // IE 8-10 support script readyState\n // IE 11+ & Firefox support stack trace\n try {\n throw new Error();\n }\n catch (err) {\n // Find the second match for the \"at\" string to get file src url from stack.\n var ieStackRegExp = /.*at [^(]*\\((.*):(.+):(.+)\\)$/ig,\n ffStackRegExp = /@([^@]*):(\\d+):(\\d+)\\s*$/ig,\n stackDetails = ieStackRegExp.exec(err.stack) || ffStackRegExp.exec(err.stack),\n scriptLocation = (stackDetails && stackDetails[1]) || false,\n line = (stackDetails && stackDetails[2]) || false,\n currentLocation = document.location.href.replace(document.location.hash, ''),\n pageSource,\n inlineScriptSourceRegExp,\n inlineScriptSource,\n scripts = document.getElementsByTagName('script'); // Live NodeList collection\n \n if (scriptLocation === currentLocation) {\n pageSource = document.documentElement.outerHTML;\n inlineScriptSourceRegExp = new RegExp('(?:[^\\\\n]+?\\\\n){0,' + (line - 2) + '}[^<]* - - diff --git a/js/gated-content/src/components/auth/CustomAuthEmailConfirm.vue b/js/gated-content/src/components/auth/CustomAuthEmailConfirm.vue new file mode 100644 index 000000000..582b8b46b --- /dev/null +++ b/js/gated-content/src/components/auth/CustomAuthEmailConfirm.vue @@ -0,0 +1,68 @@ + + + diff --git a/js/gated-content/src/router/index.js b/js/gated-content/src/router/index.js index 744e042bc..d048b4da2 100644 --- a/js/gated-content/src/router/index.js +++ b/js/gated-content/src/router/index.js @@ -3,6 +3,7 @@ import VueRouter from 'vue-router'; import Store from '@/store'; import Home from '@/views/Home.vue'; import Login from '@/views/Login.vue'; +import CustomAuthEmailConfirm from '@/components/auth/CustomAuthEmailConfirm.vue'; import NotFound from '@/views/NotFound.vue'; import VideoPage from '@/views/VideoPage.vue'; import BlogPage from '@/views/BlogPage.vue'; @@ -29,6 +30,13 @@ const routes = [ component: Login, meta: { requiresGuest: true }, }, + { + path: '/login/:id/:token/confirm', + name: 'CustomAuthEmailConfirm', + component: CustomAuthEmailConfirm, + props: true, + meta: { requiresGuest: true }, + }, { path: '/categories', name: 'CategoryListing', diff --git a/js/gated-content/src/store/modules/auth/custom.js b/js/gated-content/src/store/modules/auth/custom.js index ea77fb7ac..35671d251 100644 --- a/js/gated-content/src/store/modules/auth/custom.js +++ b/js/gated-content/src/store/modules/auth/custom.js @@ -21,11 +21,43 @@ export default { data: { recaptchaToken: data.recaptchaToken, email: data.email, + path: data.path, }, + }) + .then((response2) => { + if (response2.status === 200) { + // Call the base auth authorize action. + context.dispatch('authorize', response2.data.user); + } + return response2; + }) + .catch((error) => { + console.error(error); + throw error; + })) + .catch((error) => { + throw error; + }); + }, + async customEmailConfirmation(context, data) { + return client + .get('session/token') + .then((response) => client({ + url: context.getters.getCustomConfig.emailVerificationApiEndpoint, + method: 'post', + headers: { + 'Content-Type': 'application/json', + 'X-CSRF-Token': response.data, + }, + params: { + _format: 'json', + }, + data, }) .then((response2) => { // Call the base auth authorize action. context.dispatch('authorize', response2.data.user); + return response2; }) .catch((error) => { console.error(error); diff --git a/js/gated-content/src/views/Login.vue b/js/gated-content/src/views/Login.vue index aeb5a3451..1ec5db630 100644 --- a/js/gated-content/src/views/Login.vue +++ b/js/gated-content/src/views/Login.vue @@ -34,8 +34,6 @@ export default { return this.$store.getters.authPlugin; }, }, - mounted() { - }, methods: { loginSuccess() { this.$router.push({ name: 'Home' }); diff --git a/modules/openy_gc_auth/modules/openy_gc_auth_custom/config/install/openy_gc_auth.provider.custom.yml b/modules/openy_gc_auth/modules/openy_gc_auth_custom/config/install/openy_gc_auth.provider.custom.yml index 3644623d0..1bc31dd2f 100644 --- a/modules/openy_gc_auth/modules/openy_gc_auth_custom/config/install/openy_gc_auth.provider.custom.yml +++ b/modules/openy_gc_auth/modules/openy_gc_auth_custom/config/install/openy_gc_auth.provider.custom.yml @@ -1,2 +1,7 @@ -enable_recaptcha: 1 +enable_recaptcha: 0 api_endpoint: /openy-gc-auth/provider/custom/login +enable_email_verification: 1 +email_verification_api_endpoint: /openy-gc-auth/provider/custom/login-by-link +email_verification_link_life_time: '14400' +email_verification_text: 'Hello!
You’re just one step away from accessing your Virtual YMCA. Please open the link below to begin enjoying YMCA content made exclusively for members like you.' +verification_message: 'We have sent a verification link to the email address you provided. Please open this link and activate your account. If you do not receive an email, please try again or contact us at XXX-XXX-XXXX to ensure we have the correct email on file for your membership.' diff --git a/modules/openy_gc_auth/modules/openy_gc_auth_custom/config/install/rest.resource.openy_gc_auth_custom_confirm.yml b/modules/openy_gc_auth/modules/openy_gc_auth_custom/config/install/rest.resource.openy_gc_auth_custom_confirm.yml new file mode 100644 index 000000000..7afa44a14 --- /dev/null +++ b/modules/openy_gc_auth/modules/openy_gc_auth_custom/config/install/rest.resource.openy_gc_auth_custom_confirm.yml @@ -0,0 +1,17 @@ +langcode: en +status: true +dependencies: + module: + - openy_gc_auth_custom + - serialization + - user +id: openy_gc_auth_custom_confirm +plugin_id: openy_gc_auth_custom_confirm +granularity: resource +configuration: + methods: + - POST + formats: + - json + authentication: + - cookie diff --git a/modules/openy_gc_auth/modules/openy_gc_auth_custom/openy_gc_auth_custom.info.yml b/modules/openy_gc_auth/modules/openy_gc_auth_custom/openy_gc_auth_custom.info.yml index 203c64b3c..a9e64a15d 100644 --- a/modules/openy_gc_auth/modules/openy_gc_auth_custom/openy_gc_auth_custom.info.yml +++ b/modules/openy_gc_auth/modules/openy_gc_auth_custom/openy_gc_auth_custom.info.yml @@ -11,3 +11,4 @@ dependencies: - drupal:recaptcha - drupal:rest - drupal:openy_gc_auth + - drupal:openy_upgrade_tool diff --git a/modules/openy_gc_auth/modules/openy_gc_auth_custom/openy_gc_auth_custom.install b/modules/openy_gc_auth/modules/openy_gc_auth_custom/openy_gc_auth_custom.install index 71a114ce0..275f9a77e 100644 --- a/modules/openy_gc_auth/modules/openy_gc_auth_custom/openy_gc_auth_custom.install +++ b/modules/openy_gc_auth/modules/openy_gc_auth_custom/openy_gc_auth_custom.install @@ -5,6 +5,7 @@ * Installation file. */ +use Drupal\Core\Field\BaseFieldDefinition; use Drupal\user\Entity\Role; use Drupal\user\RoleInterface; @@ -20,6 +21,7 @@ function openy_gc_auth_custom_install() { $permissions = [ 'restful post openy_gc_auth_custom', + 'restful post openy_gc_auth_custom_confirm', ]; foreach ($permissions as $permission) { @@ -28,5 +30,46 @@ function openy_gc_auth_custom_install() { $role->save(); } } +} + +/** + * Add new base fields definitions for the gc_auth_custom_user. + */ +function openy_gc_auth_custom_update_8001() { + $bundle_of = 'gc_auth_custom_user'; + $definition_manager = \Drupal::entityDefinitionUpdateManager(); + $status = BaseFieldDefinition::create('boolean') + ->setLabel(t('User status')) + ->setDescription(t('Whether the gc_auth_custom_user is verified or blocked.')) + ->setDefaultValue(FALSE); + $verification_time = BaseFieldDefinition::create('timestamp') + ->setLabel(t('Verification time')) + ->setDescription(t('The time at which the verification email was sent.')) + ->setDefaultValue(NULL); + $verification_token = BaseFieldDefinition::create('string') + ->setLabel(t('Verification token')) + ->setDescription(t('The token that gc_auth_custom_user for account activation.')) + ->setDefaultValue(NULL); + + // Install the new definitions. + $definition_manager->installFieldStorageDefinition('status', $bundle_of, $bundle_of, $status); + $definition_manager->installFieldStorageDefinition('verification_time', $bundle_of, $bundle_of, $verification_time); + $definition_manager->installFieldStorageDefinition('verification_token', $bundle_of, $bundle_of, $verification_token); +} + +/** + * Set proper permissions to access the new rest endpoint. + */ +function openy_gc_auth_custom_update_8002() { + $config_dir = drupal_get_path('module', 'openy_gc_auth_custom'); + $config_dir .= '/config/install/'; + // Import new configuration. + $config_importer = \Drupal::service('openy_upgrade_tool.importer'); + $config_importer->setDirectory($config_dir); + $config_importer->importConfigs([ + 'rest.resource.openy_gc_auth_custom_confirm', + ]); + // Set proper permissions to access the new endpoint. + openy_gc_auth_custom_install(); } diff --git a/modules/openy_gc_auth/modules/openy_gc_auth_custom/openy_gc_auth_custom.module b/modules/openy_gc_auth/modules/openy_gc_auth_custom/openy_gc_auth_custom.module index 25713a4cf..1691786a9 100644 --- a/modules/openy_gc_auth/modules/openy_gc_auth_custom/openy_gc_auth_custom.module +++ b/modules/openy_gc_auth/modules/openy_gc_auth_custom/openy_gc_auth_custom.module @@ -87,3 +87,19 @@ function _openy_gc_auth_custom_migration_group_edit_form_submit(array &$form, Fo $plugin_manager = \Drupal::service('plugin.manager.migration'); $plugin_manager->clearCachedDefinitions(); } + +/** + * Implements hook_mail(). + */ +function openy_gc_auth_custom_mail($key, &$message, $params) { + switch ($key) { + case 'email_verification': + $site_config = \Drupal::config('system.site'); + $message['from'] = $site_config->get('mail'); + $message['subject'] = t('@site_name: Virtual Y email verification', [ + '@site_name' => $site_config->get('name'), + ]); + $message['body'][] = $params['message']; + break; + } +} diff --git a/modules/openy_gc_auth/modules/openy_gc_auth_custom/src/Entity/AuthCustomUser.php b/modules/openy_gc_auth/modules/openy_gc_auth_custom/src/Entity/AuthCustomUser.php index aa444f2ca..2b2ef1e68 100644 --- a/modules/openy_gc_auth/modules/openy_gc_auth_custom/src/Entity/AuthCustomUser.php +++ b/modules/openy_gc_auth/modules/openy_gc_auth_custom/src/Entity/AuthCustomUser.php @@ -23,6 +23,53 @@ */ class AuthCustomUser extends ContentEntityBase implements AuthCustomUserInterface { + /** + * {@inheritdoc} + */ + public function getVerificationTime() { + return $this->get('verification_time')->value; + } + + /** + * {@inheritdoc} + */ + public function setVerificationTime($timestamp) { + $this->get('verification_time')->value = $timestamp; + return $this; + } + + /** + * {@inheritdoc} + */ + public function getToken() { + return $this->get('verification_token')->value; + } + + /** + * {@inheritdoc} + */ + public function setToken($token) { + $this->get('verification_token')->value = $token; + return $this; + } + + /** + * {@inheritdoc} + */ + public function isActive() { + return $this->get('status')->value == 1; + } + + /** + * {@inheritdoc} + */ + public function activate() { + $this->get('status')->value = 1; + $this->get('verification_token')->value = ''; + $this->get('verification_time')->value = NULL; + return $this; + } + /** * {@inheritdoc} */ @@ -58,6 +105,21 @@ public static function baseFieldDefinitions(EntityTypeInterface $entity_type) { ->setLabel(t('Package Site')) ->setDescription(t('Member Package Site.')); + $fields['status'] = BaseFieldDefinition::create('boolean') + ->setLabel(t('User status')) + ->setDescription(t('Whether the gc_auth_custom_user is verified or blocked.')) + ->setDefaultValue(FALSE); + + $fields['verification_time'] = BaseFieldDefinition::create('timestamp') + ->setLabel(t('Verification time')) + ->setDescription(t('The time at which the verification email was sent.')) + ->setDefaultValue(NULL); + + $fields['verification_token'] = BaseFieldDefinition::create('string') + ->setLabel(t('Verification token')) + ->setDescription(t('The token that gc_auth_custom_user for account activation.')) + ->setDefaultValue(NULL); + return $fields; } diff --git a/modules/openy_gc_auth/modules/openy_gc_auth_custom/src/Plugin/GCIdentityProvider/Custom.php b/modules/openy_gc_auth/modules/openy_gc_auth_custom/src/Plugin/GCIdentityProvider/Custom.php index 632be17a5..9d6f97b48 100644 --- a/modules/openy_gc_auth/modules/openy_gc_auth_custom/src/Plugin/GCIdentityProvider/Custom.php +++ b/modules/openy_gc_auth/modules/openy_gc_auth_custom/src/Plugin/GCIdentityProvider/Custom.php @@ -24,6 +24,11 @@ public function defaultConfiguration():array { return [ 'enable_recaptcha' => TRUE, 'api_endpoint' => '/openy-gc-auth/provider/custom/login', + 'enable_email_verification' => TRUE, + 'email_verification_api_endpoint' => '/openy-gc-auth/provider/custom/login-by-link', + 'email_verification_link_life_time' => 14400, + 'email_verification_text' => 'Hello!
You’re just one step away from accessing your Virtual YMCA. Please open the link below to begin enjoying YMCA content made exclusively for members like you.', + 'verification_message' => 'We have sent a verification link to the email address you provided. Please open this link and activate your account. If you do not receive an email, please try again or contact us at XXX-XXX-XXXX to ensure we have the correct email on file for your membership.', ]; } @@ -50,13 +55,67 @@ public function buildConfigurationForm(array $form, FormStateInterface $form_sta ]; $form['api_endpoint'] = [ - '#title' => $this->t('API endpoint'), + '#title' => $this->t('Login form API endpoint'), '#description' => $this->t('Change this value only in case you have custom endpoint for this.'), '#type' => 'textfield', '#default_value' => $config['api_endpoint'], '#required' => TRUE, ]; + $form['verification'] = [ + '#type' => 'details', + '#title' => $this->t('Email verification'), + '#open' => TRUE, + ]; + + $form['verification']['enable_email_verification'] = [ + '#title' => $this->t('Enable Email verification'), + '#description' => $this->t('Set to TRUE if you want enable one-time login link sending to user email for verification.'), + '#type' => 'checkbox', + '#default_value' => $config['enable_email_verification'], + ]; + + $form['verification']['email_verification_api_endpoint'] = [ + '#title' => $this->t('Email verification API endpoint'), + '#description' => $this->t('Change this value only in case you have custom endpoint for this.'), + '#type' => 'textfield', + '#default_value' => $config['email_verification_api_endpoint'], + '#required' => TRUE, + ]; + + $form['verification']['email_verification_link_life_time'] = [ + '#type' => 'select', + '#title' => $this->t('Login link life time'), + '#description' => $this->t('Select the time period after which the verification link will expire.'), + '#default_value' => $config['email_verification_link_life_time'], + '#required' => TRUE, + '#options' => [ + 3600 => $this->t('1 hour'), + 7200 => $this->t('2 hours'), + 10800 => $this->t('3 hours'), + 14400 => $this->t('4 hours'), + 18000 => $this->t('5 hours'), + 86400 => $this->t('1 day'), + 172800 => $this->t('2 days'), + ], + ]; + + $form['verification']['email_verification_text'] = [ + '#title' => $this->t('Email verification text'), + '#description' => $this->t('This text will be used in the email.'), + '#type' => 'textarea', + '#default_value' => $config['email_verification_text'], + '#required' => TRUE, + ]; + + $form['verification']['verification_message'] = [ + '#title' => $this->t('Verification message'), + '#description' => $this->t('This text will be displayed in the application after unverified user tried to login.'), + '#type' => 'textarea', + '#default_value' => $config['verification_message'], + '#required' => TRUE, + ]; + return $form; } @@ -67,6 +126,11 @@ public function submitConfigurationForm(array &$form, FormStateInterface $form_s if (!$form_state->getErrors()) { $this->configuration['enable_recaptcha'] = $form_state->getValue('enable_recaptcha'); $this->configuration['api_endpoint'] = $form_state->getValue('api_endpoint'); + $this->configuration['enable_email_verification'] = $form_state->getValue('enable_email_verification'); + $this->configuration['email_verification_api_endpoint'] = $form_state->getValue('email_verification_api_endpoint'); + $this->configuration['email_verification_link_life_time'] = $form_state->getValue('email_verification_link_life_time'); + $this->configuration['email_verification_text'] = $form_state->getValue('email_verification_text'); + $this->configuration['verification_message'] = $form_state->getValue('verification_message'); parent::submitConfigurationForm($form, $form_state); } } @@ -77,7 +141,9 @@ public function submitConfigurationForm(array &$form, FormStateInterface $form_s public function getDataForApp():array { $data = parent::getDataForApp(); $data['enableRecaptcha'] = (bool) $this->configuration['enable_recaptcha']; + $data['emailVerification'] = (bool) $this->configuration['enable_email_verification']; $data['apiEndpoint'] = $this->configuration['api_endpoint']; + $data['emailVerificationApiEndpoint'] = $this->configuration['email_verification_api_endpoint']; $this->configFactory->get('recaptcha.settings')->get('site_key'); $data['reCaptchaKey'] = $this->configFactory ->get('recaptcha.settings') diff --git a/modules/openy_gc_auth/modules/openy_gc_auth_custom/src/Plugin/rest/ErrorResponseTrait.php b/modules/openy_gc_auth/modules/openy_gc_auth_custom/src/Plugin/rest/ErrorResponseTrait.php new file mode 100644 index 000000000..7add67342 --- /dev/null +++ b/modules/openy_gc_auth/modules/openy_gc_auth_custom/src/Plugin/rest/ErrorResponseTrait.php @@ -0,0 +1,30 @@ + $message, + 'status' => 'invalid', + ], $status); + } + +} diff --git a/modules/openy_gc_auth/modules/openy_gc_auth_custom/src/Plugin/rest/resource/GatedContentCustomAuthConfirm.php b/modules/openy_gc_auth/modules/openy_gc_auth_custom/src/Plugin/rest/resource/GatedContentCustomAuthConfirm.php new file mode 100644 index 000000000..080cdb6d1 --- /dev/null +++ b/modules/openy_gc_auth/modules/openy_gc_auth_custom/src/Plugin/rest/resource/GatedContentCustomAuthConfirm.php @@ -0,0 +1,142 @@ +entityTypeManager = $entity_type_manager; + $this->configFactory = $config_factory; + } + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) { + return new static( + $configuration, + $plugin_id, + $plugin_definition, + $container->get('entity_type.manager'), + $container->getParameter('serializer.formats'), + $container->get('logger.factory')->get('rest'), + $container->get('config.factory') + ); + } + + /** + * Responds to POST requests and login custom user by email. + * + * @param \Symfony\Component\HttpFoundation\Request $request + * The HTTP request object. + * + * @return \Drupal\rest\ModifiedResourceResponse + * The HTTP response object. + * + * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException + * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException + */ + public function post(Request $request) { + $content = json_decode($request->getContent(), TRUE); + if (!is_array($content) || empty($content)) { + return $this->errorResponse($this->t('Bad Request.'), 400); + } + + $provider_config = $this->configFactory->get('openy_gc_auth.provider.custom'); + $gc_user = $this->entityTypeManager + ->getStorage('gc_auth_custom_user') + ->loadByProperties([ + 'id' => $content['id'], + 'verification_token' => $content['token'], + ]); + + // Verify that the user exists. + if (empty($gc_user)) { + return $this->errorResponse($this->t('Invalid link. Please try to Sign in and verify your email one more time.'), 404); + } + + $gc_user = reset($gc_user); + if ($gc_user->getVerificationTime() + (int) $provider_config->get('email_verification_link_life_time') < time()) { + return $this->errorResponse($this->t('Verification link has expired. Please try to Sign in and verify your email one more time.'), 400); + } + + $gc_user->activate()->save(); + + // User can login. + return new ModifiedResourceResponse([ + 'message' => 'success', + 'user' => [ + 'email' => $gc_user->email->value, + 'name' => $gc_user->first_name->value, + 'primary' => (bool) $gc_user->primary->value, + ], + 'status' => 'ok', + ], 200); + } + +} diff --git a/modules/openy_gc_auth/modules/openy_gc_auth_custom/src/Plugin/rest/resource/GatedContentCustomAuthentication.php b/modules/openy_gc_auth/modules/openy_gc_auth_custom/src/Plugin/rest/resource/GatedContentCustomAuthentication.php index 95b8aab26..5eb0aaf32 100644 --- a/modules/openy_gc_auth/modules/openy_gc_auth_custom/src/Plugin/rest/resource/GatedContentCustomAuthentication.php +++ b/modules/openy_gc_auth/modules/openy_gc_auth_custom/src/Plugin/rest/resource/GatedContentCustomAuthentication.php @@ -5,8 +5,11 @@ use Drupal\Component\Utility\EmailValidatorInterface; use Drupal\Core\Config\ConfigFactoryInterface; use Drupal\Core\Entity\EntityTypeManagerInterface; +use Drupal\Core\Mail\MailManagerInterface; use Drupal\Core\Plugin\ContainerFactoryPluginInterface; use Drupal\Core\StringTranslation\StringTranslationTrait; +use Drupal\Component\Utility\Crypt; +use Drupal\openy_gc_auth_custom\Plugin\rest\ErrorResponseTrait; use Drupal\rest\ModifiedResourceResponse; use Drupal\rest\Plugin\ResourceBase; use Psr\Log\LoggerInterface; @@ -29,6 +32,7 @@ class GatedContentCustomAuthentication extends ResourceBase implements ContainerFactoryPluginInterface { use StringTranslationTrait; + use ErrorResponseTrait; /** * The entity type targeted by this resource. @@ -51,6 +55,13 @@ class GatedContentCustomAuthentication extends ResourceBase implements Container */ protected $configFactory; + /** + * The mail manager. + * + * @var \Drupal\Core\Mail\MailManagerInterface + */ + protected $mailManager; + /** * Constructs a GatedContentCustomAuthentication. * @@ -70,6 +81,8 @@ class GatedContentCustomAuthentication extends ResourceBase implements Container * Validates email addresses. * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory * The factory for configuration objects. + * @param \Drupal\Core\Mail\MailManagerInterface $mail_manager + * The mail manager. */ public function __construct( array $configuration, @@ -79,11 +92,13 @@ public function __construct( array $serializer_formats, LoggerInterface $logger, EmailValidatorInterface $validator, - ConfigFactoryInterface $config_factory) { + ConfigFactoryInterface $config_factory, + MailManagerInterface $mail_manager) { parent::__construct($configuration, $plugin_id, $plugin_definition, $serializer_formats, $logger); $this->entityTypeManager = $entity_type_manager; $this->emailValidator = $validator; $this->configFactory = $config_factory; + $this->mailManager = $mail_manager; } /** @@ -98,7 +113,8 @@ public static function create(ContainerInterface $container, array $configuratio $container->getParameter('serializer.formats'), $container->get('logger.factory')->get('rest'), $container->get('email.validator'), - $container->get('config.factory') + $container->get('config.factory'), + $container->get('plugin.manager.mail') ); } @@ -123,19 +139,9 @@ public function post(Request $request) { $provider_config = $this->configFactory->get('openy_gc_auth.provider.custom'); if ($provider_config->get('enable_recaptcha')) { // Validate recaptchaToken if enabled in the provider config. - if (!$content['recaptchaToken']) { - return $this->errorResponse($this->t('ReCaptcha token required.'), 400); - } - - $config = $this->configFactory->get('recaptcha.settings'); - $recaptcha_secret_key = $config->get('secret_key'); - $recaptcha = new ReCaptcha($recaptcha_secret_key, new Drupal8Post()); - if ($config->get('verify_hostname')) { - $recaptcha->setExpectedHostname($_SERVER['SERVER_NAME']); - } - $resp = $recaptcha->verify($content['recaptchaToken'], $request->getClientIp()); - if (!$resp->isSuccess()) { - return $this->errorResponse($this->t('ReCaptcha token invalid.'), 400); + $validation_result = $this->validateRecaptcha($content, $request); + if ($validation_result instanceof ModifiedResourceResponse) { + return $validation_result; } } @@ -154,6 +160,16 @@ public function post(Request $request) { ]), 404); } $user = reset($gc_users); + + if ($provider_config->get('enable_email_verification')) { + if (!$user->isActive()) { + $verification_result = $this->sendEmailVerification($user, $content, $request, $provider_config); + if ($verification_result instanceof ModifiedResourceResponse) { + return $verification_result; + } + } + } + // User can login. return new ModifiedResourceResponse([ 'message' => 'success', @@ -167,21 +183,56 @@ public function post(Request $request) { } /** - * Error Response. - * - * @param string $message - * The error message. - * @param int $status - * The HTTP status code for error. - * - * @return \Drupal\rest\ModifiedResourceResponse - * The HTTP response object. + * Helper function for reCaptcha validation. */ - protected function errorResponse($message, $status) { + protected function validateRecaptcha($content, $request) { + if (!$content['recaptchaToken']) { + return $this->errorResponse($this->t('ReCaptcha token required.'), 400); + } + + $config = $this->configFactory->get('recaptcha.settings'); + $recaptcha_secret_key = $config->get('secret_key'); + $recaptcha = new ReCaptcha($recaptcha_secret_key, new Drupal8Post()); + if ($config->get('verify_hostname')) { + $recaptcha->setExpectedHostname($_SERVER['SERVER_NAME']); + } + $resp = $recaptcha->verify($content['recaptchaToken'], $request->getClientIp()); + if (!$resp->isSuccess()) { + return $this->errorResponse($this->t('ReCaptcha token invalid.'), 400); + } + + return TRUE; + } + + /** + * Helper function for verification email sending. + */ + protected function sendEmailVerification($user, $content, $request, $provider_config) { + $request_time = $request->server->get('REQUEST_TIME'); + $token = Crypt::hashBase64($content['email'] . $request_time); + // Generate confirmation link for application, example: + // https://{HOST}/virtual-ymca#/login/{ID}/{TOKEN}/confirm + $path = implode('/', [ + $request->getSchemeAndHttpHost() . $content['path'] . '#/login', + $user->id(), + $token, + 'confirm', + ]); + + $user->setToken($token) + ->setVerificationTime($request_time) + ->save(); + + $params = [ + 'message' => $provider_config->get('email_verification_text') . '
', + ]; + $params['message'] .= 'Click to verify your email'; + $this->mailManager->mail('openy_gc_auth_custom', 'email_verification', $content['email'], 'en', $params, NULL, TRUE); + return new ModifiedResourceResponse([ - 'message' => $message, - 'status' => 'invalid', - ], $status); + 'message' => $provider_config->get('verification_message'), + 'status' => 'Accepted', + ], 202); } } diff --git a/modules/openy_gc_demo/migrations/migrate_plus.migration.virtual_y_gc_auth_custom_user.yml b/modules/openy_gc_demo/migrations/migrate_plus.migration.virtual_y_gc_auth_custom_user.yml new file mode 100644 index 000000000..cbb3ab20f --- /dev/null +++ b/modules/openy_gc_demo/migrations/migrate_plus.migration.virtual_y_gc_auth_custom_user.yml @@ -0,0 +1,66 @@ +langcode: en +status: true +dependencies: + enforced: + module: + - openy_gc_demo + - openy_gc_auth_custom +id: virtual_y_gc_auth_custom_user +migration_tags: + - openy_complete_installation +migration_group: virtual_y +label: 'GC auth custom users' +source: + plugin: embedded_data + data_rows: + - + id: 1 + member_id: 123456 + first_name: 'John' + email: 'johndoe@test.com' + - + id: 2 + member_id: 678912 + first_name: 'Adam' + email: 'adamk@verizon.net' + - + id: 3 + member_id: 345678 + first_name: 'Nelson' + email: 'nelson@gmail.com' + - + id: 4 + member_id: 901234 + first_name: 'Jessica' + email: 'twoflower@yahoo.com' + - + id: 5 + member_id: 567890 + first_name: 'Desmond' + email: 'pfitza@msn.com' + - + id: 6 + member_id: 987654 + first_name: 'John' + email: 'joehall@live.com' + ids: + id: + type: integer +process: + status: + plugin: default_value + default_value: 0 + primary: + plugin: default_value + default_value: 1 + package_name: + plugin: default_value + default_value: 'Virtual Y' + package_site: + plugin: default_value + default_value: 'Test YMCA' + member_id: member_id + first_name: first_name + email: email +destination: + plugin: entity:gc_auth_custom_user From 7c6a84b2ee3adf2091d6a97111d023863c29a9c2 Mon Sep 17 00:00:00 2001 From: Igor Karpilenko Date: Mon, 27 Jul 2020 14:18:05 +0300 Subject: [PATCH 3/9] [VYMCA-64] Add full_html to messages in settings form --- js/gated-content/dist/gated-content.umd.min.js | 2 +- js/gated-content/src/components/auth/CustomAuth.vue | 2 +- .../src/Plugin/GCIdentityProvider/Custom.php | 11 +++++++---- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/js/gated-content/dist/gated-content.umd.min.js b/js/gated-content/dist/gated-content.umd.min.js index 29d4078e9..eee6ce5c0 100644 --- a/js/gated-content/dist/gated-content.umd.min.js +++ b/js/gated-content/dist/gated-content.umd.min.js @@ -15,4 +15,4 @@ function n(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as v0.8.1 (c) Kyle Simpson MIT License: http://getify.mit-license.org */ -(function(e,n,r){n[e]=n[e]||r(),t.exports&&(t.exports=n[e])})("Promise",p,(function(){var t,e,n,r=Object.prototype.toString,i="undefined"!=typeof setImmediate?function(t){return setImmediate(t)}:setTimeout;try{Object.defineProperty({},"x",{}),t=function(t,e,n,r){return Object.defineProperty(t,e,{value:n,writable:!0,configurable:!1!==r})}}catch(g){t=function(t,e,n){return t[e]=n,t}}function o(t,r){n.add(t,r),e||(e=i(n.drain))}function a(t){var e,n=typeof t;return null==t||"object"!=n&&"function"!=n||(e=t.then),"function"==typeof e&&e}function s(){for(var t=0;t0&&o(s,n))}catch(g){l.call(new d(n),g)}}}function l(t){var e=this;e.triggered||(e.triggered=!0,e.def&&(e=e.def),e.msg=t,e.state=2,e.chain.length>0&&o(s,e))}function f(t,e,n,r){for(var i=0;i1&&void 0!==arguments[1]?arguments[1]:{};return x.reduce((function(e,n){var r=t.getAttribute("data-vimeo-".concat(n));return(r||""===r)&&(e[n]=""===r?1:r),e}),e)}function k(t,e){var n=t.html;if(!e)throw new TypeError("An element must be provided");if(null!==e.getAttribute("data-vimeo-initialized"))return e.querySelector("iframe");var r=document.createElement("div");return r.innerHTML=n,e.appendChild(r.firstChild),e.setAttribute("data-vimeo-initialized","true"),e.querySelector("iframe")}function C(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},n=arguments.length>2?arguments[2]:void 0;return new Promise((function(r,i){if(!c(t))throw new TypeError("“".concat(t,"” is not a vimeo.com url."));var o="https://vimeo.com/api/oembed.json?url=".concat(encodeURIComponent(t));for(var a in e)e.hasOwnProperty(a)&&(o+="&".concat(a,"=").concat(encodeURIComponent(e[a])));var s="XDomainRequest"in window?new XDomainRequest:new XMLHttpRequest;s.open("GET",o,!0),s.onload=function(){if(404!==s.status)if(403!==s.status)try{var e=JSON.parse(s.responseText);if(403===e.domain_status_code)return k(e,n),void i(new Error("“".concat(t,"” is not embeddable.")));r(e)}catch(o){i(o)}else i(new Error("“".concat(t,"” is not embeddable.")));else i(new Error("“".concat(t,"” was not found.")))},s.onerror=function(){var t=s.status?" (".concat(s.status,")"):"";i(new Error("There was an error fetching the embed code from Vimeo".concat(t,".")))},s.send()}))}function E(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:document,e=[].slice.call(t.querySelectorAll("[data-vimeo-id], [data-vimeo-url]")),n=function(t){"console"in window&&console.error&&console.error("There was an error creating an embed: ".concat(t))};e.forEach((function(t){try{if(null!==t.getAttribute("data-vimeo-defer"))return;var e=S(t),r=l(e);C(r,e,t).then((function(e){return k(e,t)})).catch(n)}catch(i){n(i)}}))}function O(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:document;if(!window.VimeoPlayerResizeEmbeds_){window.VimeoPlayerResizeEmbeds_=!0;var e=function(e){if(c(e.origin)&&e.data&&"spacechange"===e.data.event)for(var n=t.querySelectorAll("iframe"),r=0;r=8&&i<10&&(r=JSON.stringify(r)),t.element.contentWindow.postMessage(r,t.origin)}}function A(t,e){e=j(e);var n,r=[];if(e.event){if("error"===e.event){var i=y(t,e.data.method);i.forEach((function(n){var r=new Error(e.data.message);r.name=e.data.name,n.reject(r),b(t,e.data.method,n)}))}r=y(t,"event:".concat(e.event)),n=e.data}else if(e.method){var o=_(t,e.method);o&&(r.push(o),n=e.value)}r.forEach((function(e){try{if("function"===typeof e)return void e.call(t,n);e.resolve(n)}catch(r){}}))}var T=new WeakMap,$=new WeakMap,P=function(){function t(e){var r=this,i=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};if(n(this,t),window.jQuery&&e instanceof jQuery&&(e.length>1&&window.console&&console.warn&&console.warn("A jQuery object with multiple elements was passed, using the first element."),e=e[0]),"undefined"!==typeof document&&"string"===typeof e&&(e=document.getElementById(e)),!s(e))throw new TypeError("You must pass either a valid element or a valid id.");if("IFRAME"!==e.nodeName){var o=e.querySelector("iframe");o&&(e=o)}if("IFRAME"===e.nodeName&&!c(e.getAttribute("src")||""))throw new Error("The player element passed isn’t a Vimeo embed.");if(T.has(e))return T.get(e);this._window=e.ownerDocument.defaultView,this.element=e,this.origin="*";var a=new v((function(t,n){if(r._onMessage=function(e){if(c(e.origin)&&r.element.contentWindow===e.source){"*"===r.origin&&(r.origin=e.origin);var i=j(e.data),o=i&&"error"===i.event,a=o&&i.data&&"ready"===i.data.method;if(a){var s=new Error(i.data.message);return s.name=i.data.name,void n(s)}var u=i&&"ready"===i.event,l=i&&"ping"===i.method;if(u||l)return r.element.setAttribute("data-ready","true"),void t();A(r,i)}},r._window.addEventListener("message",r._onMessage),"IFRAME"!==r.element.nodeName){var o=S(e,i),a=l(o);C(a,o,e).then((function(t){var n=k(t,e);return r.element=n,r._originalElement=e,w(e,n),T.set(r.element,r),t})).catch(n)}}));return $.set(this,a),T.set(this.element,this),"IFRAME"===this.element.nodeName&&L(this,"ping"),this}return i(t,[{key:"callMethod",value:function(t){var e=this,n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};return new v((function(r,i){return e.ready().then((function(){m(e,t,{resolve:r,reject:i}),L(e,t,n)})).catch(i)}))}},{key:"get",value:function(t){var e=this;return new v((function(n,r){return t=a(t,"get"),e.ready().then((function(){m(e,t,{resolve:n,reject:r}),L(e,t)})).catch(r)}))}},{key:"set",value:function(t,e){var n=this;return new v((function(r,i){if(t=a(t,"set"),void 0===e||null===e)throw new TypeError("There must be a value to set.");return n.ready().then((function(){m(n,t,{resolve:r,reject:i}),L(n,t,e)})).catch(i)}))}},{key:"on",value:function(t,e){if(!t)throw new TypeError("You must pass an event name.");if(!e)throw new TypeError("You must pass a callback function.");if("function"!==typeof e)throw new TypeError("The callback must be a function.");var n=y(this,"event:".concat(t));0===n.length&&this.callMethod("addEventListener",t).catch((function(){})),m(this,"event:".concat(t),e)}},{key:"off",value:function(t,e){if(!t)throw new TypeError("You must pass an event name.");if(e&&"function"!==typeof e)throw new TypeError("The callback must be a function.");var n=b(this,"event:".concat(t),e);n&&this.callMethod("removeEventListener",t).catch((function(t){}))}},{key:"loadVideo",value:function(t){return this.callMethod("loadVideo",t)}},{key:"ready",value:function(){var t=$.get(this)||new v((function(t,e){e(new Error("Unknown player. Probably unloaded."))}));return v.resolve(t)}},{key:"addCuePoint",value:function(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};return this.callMethod("addCuePoint",{time:t,data:e})}},{key:"removeCuePoint",value:function(t){return this.callMethod("removeCuePoint",t)}},{key:"enableTextTrack",value:function(t,e){if(!t)throw new TypeError("You must pass a language.");return this.callMethod("enableTextTrack",{language:t,kind:e})}},{key:"disableTextTrack",value:function(){return this.callMethod("disableTextTrack")}},{key:"pause",value:function(){return this.callMethod("pause")}},{key:"play",value:function(){return this.callMethod("play")}},{key:"requestFullscreen",value:function(){return this.callMethod("requestFullscreen")}},{key:"exitFullscreen",value:function(){return this.callMethod("exitFullscreen")}},{key:"getFullscreen",value:function(){return this.get("fullscreen")}},{key:"unload",value:function(){return this.callMethod("unload")}},{key:"destroy",value:function(){var t=this;return new v((function(e){$.delete(t),T.delete(t.element),t._originalElement&&(T.delete(t._originalElement),t._originalElement.removeAttribute("data-vimeo-initialized")),t.element&&"IFRAME"===t.element.nodeName&&t.element.parentNode&&t.element.parentNode.removeChild(t.element),t._window.removeEventListener("message",t._onMessage),e()}))}},{key:"getAutopause",value:function(){return this.get("autopause")}},{key:"setAutopause",value:function(t){return this.set("autopause",t)}},{key:"getBuffered",value:function(){return this.get("buffered")}},{key:"getChapters",value:function(){return this.get("chapters")}},{key:"getCurrentChapter",value:function(){return this.get("currentChapter")}},{key:"getColor",value:function(){return this.get("color")}},{key:"setColor",value:function(t){return this.set("color",t)}},{key:"getCuePoints",value:function(){return this.get("cuePoints")}},{key:"getCurrentTime",value:function(){return this.get("currentTime")}},{key:"setCurrentTime",value:function(t){return this.set("currentTime",t)}},{key:"getDuration",value:function(){return this.get("duration")}},{key:"getEnded",value:function(){return this.get("ended")}},{key:"getLoop",value:function(){return this.get("loop")}},{key:"setLoop",value:function(t){return this.set("loop",t)}},{key:"setMuted",value:function(t){return this.set("muted",t)}},{key:"getMuted",value:function(){return this.get("muted")}},{key:"getPaused",value:function(){return this.get("paused")}},{key:"getPlaybackRate",value:function(){return this.get("playbackRate")}},{key:"setPlaybackRate",value:function(t){return this.set("playbackRate",t)}},{key:"getPlayed",value:function(){return this.get("played")}},{key:"getSeekable",value:function(){return this.get("seekable")}},{key:"getSeeking",value:function(){return this.get("seeking")}},{key:"getTextTracks",value:function(){return this.get("textTracks")}},{key:"getVideoEmbedCode",value:function(){return this.get("videoEmbedCode")}},{key:"getVideoId",value:function(){return this.get("videoId")}},{key:"getVideoTitle",value:function(){return this.get("videoTitle")}},{key:"getVideoWidth",value:function(){return this.get("videoWidth")}},{key:"getVideoHeight",value:function(){return this.get("videoHeight")}},{key:"getVideoUrl",value:function(){return this.get("videoUrl")}},{key:"getVolume",value:function(){return this.get("volume")}},{key:"setVolume",value:function(t){return this.set("volume",t)}}]),t}();o||(E(),O()),e["a"]=P}).call(this,n("c8ba"))},"861d":function(t,e){t.exports=function(t){return"object"===typeof t?null!==t:"function"===typeof t}},"87d8":function(t,e,n){"use strict";t.exports=t=>encodeURIComponent(t).replace(/[!'()*]/g,t=>"%"+t.charCodeAt(0).toString(16).toUpperCase())},8875:function(t,e,n){var r,i,o;(function(n,a){i=[],r=a,o="function"===typeof r?r.apply(e,i):r,void 0===o||(t.exports=o)})("undefined"!==typeof self&&self,(function(){function t(){if(document.currentScript)return document.currentScript;try{throw new Error}catch(f){var t,e,n,r=/.*at [^(]*\((.*):(.+):(.+)\)$/gi,i=/@([^@]*):(\d+):(\d+)\s*$/gi,o=r.exec(f.stack)||i.exec(f.stack),a=o&&o[1]||!1,s=o&&o[2]||!1,u=document.location.href.replace(document.location.hash,""),c=document.getElementsByTagName("script");a===u&&(t=document.documentElement.outerHTML,e=new RegExp("(?:[^\\n]+?\\n){0,"+(s-2)+"}[^<]*