├── .babelrc ├── .editorconfig ├── .eslintignore ├── .eslintrc ├── .gitignore ├── .prettierrc.json ├── .tern-project ├── .vscode └── settings.json ├── CODE_OF_CONDUCT.md ├── README.md ├── bower.json ├── build └── build.rollup.js ├── dist ├── vue-authenticate.common.js ├── vue-authenticate.esm.js ├── vue-authenticate.js └── vue-authenticate.min.js ├── package-lock.json ├── package.json ├── src ├── authenticate.js ├── globals.js ├── index.js ├── oauth │ ├── oauth1.js │ ├── oauth2.js │ └── popup.js ├── options.js ├── promise.js ├── storage.js ├── storage │ ├── cookie-storage.js │ ├── local-storage.js │ ├── memory-storage.js │ └── session-storage.js └── utils.js └── yarn.lock /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | [ 4 | "@babel/preset-env", 5 | { 6 | "modules": false 7 | } 8 | ] 9 | ], 10 | "plugins": ["external-helpers"] 11 | } -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | 3 | root = true 4 | 5 | [*] 6 | charset = utf-8 7 | indent_style = space 8 | indent_size = 2 9 | end_of_line = lf 10 | insert_final_newline = true 11 | trim_trailing_whitespace = true 12 | 13 | [*.md] 14 | insert_final_newline = false 15 | trim_trailing_whitespace = false 16 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | flow 2 | dist 3 | packages 4 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "parser": "babel-eslint", 4 | "parserOptions": { 5 | "sourceType": "module" 6 | }, 7 | "env": { 8 | "browser": true, 9 | }, 10 | "extends": "standard", 11 | "plugins": [ 12 | "html" 13 | ], 14 | "rules": { 15 | "arrow-parens": 0, 16 | "generator-star-spacing': 0 17 | } 18 | } 19 | 20 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Dependency directory 3 | node_modules 4 | bower_components 5 | 6 | Thumbs.db 7 | .DS_Store 8 | 9 | npm-debug.log* 10 | yarn-debug.log* 11 | yarn-error.log* 12 | 13 | # Editor directories and files 14 | .idea 15 | *.suo 16 | *.ntvs* 17 | *.njsproj 18 | *.sln 19 | *.iml 20 | .vscode 21 | settings.json 22 | jsconfig.json 23 | -------------------------------------------------------------------------------- /.prettierrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "trailingComma": "es5", 3 | "tabWidth": 2, 4 | "semi": true, 5 | "singleQuote": true, 6 | "useTabs": false, 7 | "printWidth": 80, 8 | "arrowParens": "avoid" 9 | } 10 | -------------------------------------------------------------------------------- /.tern-project: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": { 3 | "es_modules": {}, 4 | "node": {} 5 | }, 6 | "libs": [ 7 | "ecma5", 8 | "ecma6", 9 | "react", 10 | "browser" 11 | ], 12 | "ecmaVersion": 6 13 | } 14 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "eslint.enable": false 3 | } -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Code of Conduct 2 | 3 | Don't be an asshole. 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [**WARNING**]: README file is currently in process of rewrite and will be released soon. 2 | 3 | # vue-authenticate 4 | 5 | [![Join the chat at https://gitter.im/vuejs-auth/vue-authenticate](https://badges.gitter.im/vue-authenticate/Lobby.svg)](https://gitter.im/vuejs-auth/vue-authenticate?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) 6 | 7 | **vue-authenticate** is easily configurable solution for [Vue.js](https://vuejs.org/) that provides local login/registration as well as Social login using Github, Facebook, Google and other OAuth providers. 8 | 9 | 10 | 11 | The best part about this library is that it is not strictly coupled to one request handling library like [vue-axios](https://github.com/imcvampire/vue-axios). You will be able to use it with different libraries. 12 | 13 | For now it is tested to work with [vue-resource](https://github.com/pagekit/vue-resource) and [axios](https://github.com/mzabriskie/axios) (using [vue-axios](https://github.com/imcvampire/vue-axios) wrapper). 14 | 15 | **WARNING:** From version 1.3.0 default request library is `axios` using `vue-axios` wrapper plugin. 16 | 17 | This library was inspired by well known authentication library for Angular called [Satellizer](https://github.com/sahat/satellizer) developed by [Sahat Yalkabov](http://sahatyalkabov.com). They share almost identical configuration and API so you can easily switch from Angular to Vue.js project. 18 | 19 | ## Supported OAuth providers and configurations 20 | 21 | 1. Facebook (https://github.com/dgrubelic/vue-authenticate/blob/master/src/options.js#L21) 22 | 2. Google (https://github.com/dgrubelic/vue-authenticate/blob/master/src/options.js#L34) 23 | 3. Github (https://github.com/dgrubelic/vue-authenticate/blob/master/src/options.js#L49) 24 | 4. Instagram (https://github.com/dgrubelic/vue-authenticate/blob/master/src/options.js#L61) 25 | 5. Twitter (https://github.com/dgrubelic/vue-authenticate/blob/master/src/options.js#L72) 26 | 6. Bitbucket (https://github.com/dgrubelic/vue-authenticate/blob/master/src/options.js#L81) 27 | 7. LinkedIn (https://github.com/dgrubelic/vue-authenticate/blob/master/src/options.js#L93) 28 | 8. Microsoft Live (https://github.com/dgrubelic/vue-authenticate/blob/master/src/options.js#L106) 29 | 30 | ## Installation 31 | ```bash 32 | npm install vue-authenticate 33 | ``` 34 | 35 | ## Usage 36 | ```javascript 37 | import Vue from 'vue' 38 | import VueAxios from 'vue-axios' 39 | import VueAuthenticate from 'vue-authenticate' 40 | import axios from 'axios'; 41 | 42 | Vue.use(VueAxios, axios) 43 | Vue.use(VueAuthenticate, { 44 | baseUrl: 'http://localhost:3000', // Your API domain 45 | 46 | providers: { 47 | github: { 48 | clientId: '', 49 | redirectUri: 'http://localhost:8080/auth/callback' // Your client app URL 50 | } 51 | } 52 | }) 53 | ``` 54 | 55 | ### Email & password login and registration 56 | ```javascript 57 | new Vue({ 58 | methods: { 59 | login: function () { 60 | this.$auth.login({ email, password }).then(function () { 61 | // Execute application logic after successful login 62 | }) 63 | }, 64 | 65 | register: function () { 66 | this.$auth.register({ name, email, password }).then(function () { 67 | // Execute application logic after successful registration 68 | }) 69 | } 70 | } 71 | }) 72 | ``` 73 | 74 | ```html 75 | 76 | 77 | ``` 78 | 79 | ### Social account authentication 80 | 81 | ```javascript 82 | new Vue({ 83 | methods: { 84 | authenticate: function (provider) { 85 | this.$auth.authenticate(provider).then(function () { 86 | // Execute application logic after successful social authentication 87 | }) 88 | } 89 | } 90 | }) 91 | ``` 92 | 93 | ```html 94 | 95 | 96 | 97 | 98 | ``` 99 | 100 | ### Vuex authentication 101 | 102 | #### Import and initialize all required libraries 103 | 104 | ```javascript 105 | // ES6 example 106 | import Vue from 'vue' 107 | import Vuex from 'vuex' 108 | import VueAxios from 'vue-axios' 109 | import { VueAuthenticate } from 'vue-authenticate' 110 | import axios from 'axios'; 111 | 112 | Vue.use(Vuex) 113 | Vue.use(VueAxios, axios) 114 | 115 | const vueAuth = new VueAuthenticate(Vue.prototype.$http, { 116 | baseUrl: 'http://localhost:4000' 117 | }) 118 | ``` 119 | 120 | ```javascript 121 | // CommonJS example 122 | var Vue = require('vue') 123 | var Vuex = require('vuex') 124 | var VueAxios = require('vue-axios') 125 | var VueAuthenticate = require('vue-authenticate') 126 | var axios = require('axios'); 127 | 128 | Vue.use(Vuex) 129 | Vue.use(VueAxios, axios) 130 | 131 | // ES5, CommonJS example 132 | var vueAuth = VueAuthenticate.factory(Vue.prototype.$http, { 133 | baseUrl: 'http://localhost:4000' 134 | }) 135 | ``` 136 | 137 | Once you have created VueAuthenticate instance, you can use it in Vuex store like this: 138 | 139 | ```javascript 140 | export default new Vuex.Store({ 141 | 142 | // You can use it as state property 143 | state: { 144 | isAuthenticated: false 145 | }, 146 | 147 | // You can use it as a state getter function (probably the best solution) 148 | getters: { 149 | isAuthenticated () { 150 | return vueAuth.isAuthenticated() 151 | } 152 | }, 153 | 154 | // Mutation for when you use it as state property 155 | mutations: { 156 | isAuthenticated (state, payload) { 157 | state.isAuthenticated = payload.isAuthenticated 158 | } 159 | }, 160 | 161 | actions: { 162 | 163 | // Perform VueAuthenticate login using Vuex actions 164 | login (context, payload) { 165 | 166 | vueAuth.login(payload.user, payload.requestOptions).then((response) => { 167 | context.commit('isAuthenticated', { 168 | isAuthenticated: vueAuth.isAuthenticated() 169 | }) 170 | }) 171 | 172 | } 173 | } 174 | }) 175 | ``` 176 | 177 | Later in Vue component, you can dispatch Vuex state action like this 178 | 179 | ```javascript 180 | // You define your store logic here 181 | import store from './store.js' 182 | 183 | new Vue({ 184 | store, 185 | 186 | computed: { 187 | isAuthenticated: function () { 188 | return this.$store.getters.isAuthenticated() 189 | } 190 | }, 191 | 192 | methods: { 193 | login () { 194 | this.$store.dispatch('login', { user, requestOptions }) 195 | } 196 | } 197 | }) 198 | ``` 199 | 200 | ### Custom request and response interceptors 201 | 202 | You can easily setup custom request and response interceptors if you use different request handling library. 203 | 204 | **Important**: You must set both `request` and `response` interceptors at all times. 205 | 206 | ```javascript 207 | 208 | /** 209 | * This is example for request and response interceptors for axios library 210 | */ 211 | 212 | Vue.use(VueAuthenticate, { 213 | bindRequestInterceptor: function () { 214 | this.$http.interceptors.request.use((config) => { 215 | if (this.isAuthenticated()) { 216 | config.headers['Authorization'] = [ 217 | this.options.tokenType, this.getToken() 218 | ].join(' ') 219 | } else { 220 | delete config.headers['Authorization'] 221 | } 222 | return config 223 | }) 224 | }, 225 | 226 | bindResponseInterceptor: function () { 227 | this.$http.interceptors.response.use((response) => { 228 | this.setToken(response) 229 | return response 230 | }) 231 | } 232 | }) 233 | 234 | ``` 235 | 236 | ## License 237 | 238 | The MIT License (MIT) 239 | 240 | Copyright (c) 2017 Davor Grubelić 241 | 242 | Permission is hereby granted, free of charge, to any person obtaining a copy of 243 | this software and associated documentation files (the "Software"), to deal in 244 | the Software without restriction, including without limitation the rights to 245 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 246 | the Software, and to permit persons to whom the Software is furnished to do so, 247 | subject to the following conditions: 248 | 249 | The above copyright notice and this permission notice shall be included in all 250 | copies or substantial portions of the Software. 251 | 252 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 253 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 254 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 255 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 256 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 257 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 258 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue-authenticate", 3 | "version": "1.5.0", 4 | "main": "dist/vue-authenticate.js", 5 | "homepage": "https://github.com/dgrubelic/vue-authenticate", 6 | "ignore": [] 7 | } 8 | -------------------------------------------------------------------------------- /build/build.rollup.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs'); 2 | var rollup = require('rollup'); 3 | var uglify = require('uglify-js'); 4 | var buble = require('@rollup/plugin-buble'); 5 | var uglify = require('rollup-plugin-uglify').uglify; 6 | var rollupBanner = require('rollup-plugin-banner').default; 7 | var package = require('../package.json'); 8 | 9 | var banner = 10 | 'vue-authenticate v' + 11 | package.version + 12 | '\n' + 13 | 'https://github.com/dgrubelic/vue-authenticate\n' + 14 | 'Released under the MIT License.\n'; 15 | 16 | function buildSource(inputOptions, outputOptions) { 17 | rollup 18 | .rollup(inputOptions) 19 | .then(function (bundle) { 20 | return bundle.generate(outputOptions).then(function (output) { 21 | bundle.write(outputOptions); 22 | }); 23 | }) 24 | .catch(logError); 25 | } 26 | 27 | buildSource( 28 | { 29 | input: 'src/index.js', 30 | plugins: [buble(), rollupBanner(banner)], 31 | }, 32 | { 33 | file: 'dist/vue-authenticate.js', 34 | format: 'umd', 35 | name: 'VueAuthenticate', 36 | } 37 | ); 38 | 39 | buildSource( 40 | { 41 | input: 'src/index.js', 42 | plugins: [buble(), uglify(), rollupBanner(banner)], 43 | }, 44 | { 45 | file: 'dist/vue-authenticate.min.js', 46 | format: 'umd', 47 | name: 'VueAuthenticate', 48 | } 49 | ); 50 | 51 | buildSource( 52 | { 53 | input: 'src/index.js', 54 | plugins: [rollupBanner(banner)], 55 | }, 56 | { 57 | file: 'dist/vue-authenticate.esm.js', 58 | format: 'es', 59 | } 60 | ); 61 | 62 | buildSource( 63 | { 64 | input: 'src/index.js', 65 | plugins: [rollupBanner(banner)], 66 | }, 67 | { 68 | file: 'dist/vue-authenticate.common.js', 69 | format: 'cjs', 70 | } 71 | ); 72 | 73 | function logError(e) { 74 | console.error(e); 75 | } 76 | 77 | function getSize(code) { 78 | return (((code && code.length) || 0) / 1024).toFixed(2) + 'kb'; 79 | } 80 | 81 | function blue(str) { 82 | return '\x1b[1m\x1b[34m' + str + '\x1b[39m\x1b[22m'; 83 | } 84 | -------------------------------------------------------------------------------- /dist/vue-authenticate.esm.js: -------------------------------------------------------------------------------- 1 | /** 2 | * vue-authenticate v1.5.0 3 | * https://github.com/dgrubelic/vue-authenticate 4 | * Released under the MIT License. 5 | * 6 | */ 7 | 8 | if (typeof Object.assign != 'function') { 9 | Object.assign = function (target, varArgs) { 10 | if (target == null) { 11 | throw new TypeError('Cannot convert undefined or null to object'); 12 | } 13 | 14 | var to = Object(target); 15 | 16 | for (var index = 1; index < arguments.length; index++) { 17 | var nextSource = arguments[index]; 18 | 19 | if (nextSource != null) { 20 | // Skip over if undefined or null 21 | for (var nextKey in nextSource) { 22 | // Avoid bugs when hasOwnProperty is shadowed 23 | if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) { 24 | to[nextKey] = nextSource[nextKey]; 25 | } 26 | } 27 | } 28 | } 29 | return to; 30 | }; 31 | } 32 | 33 | function camelCase(name) { 34 | return name.replace(/([\:\-\_]+(.))/g, function ( 35 | _, 36 | separator, 37 | letter, 38 | offset 39 | ) { 40 | return offset ? letter.toUpperCase() : letter; 41 | }); 42 | } 43 | 44 | function isUndefined(value) { 45 | return typeof value === 'undefined'; 46 | } 47 | 48 | function isObject(value) { 49 | return value !== null && typeof value === 'object'; 50 | } 51 | 52 | function isString(value) { 53 | return typeof value === 'string'; 54 | } 55 | 56 | function isFunction(value) { 57 | return typeof value === 'function'; 58 | } 59 | 60 | function objectExtend(a, b) { 61 | // Don't touch 'null' or 'undefined' objects. 62 | if (a == null || b == null) { 63 | return a; 64 | } 65 | 66 | Object.keys(b).forEach(function (key) { 67 | if (Object.prototype.toString.call(b[key]) == '[object Object]') { 68 | if (Object.prototype.toString.call(a[key]) != '[object Object]') { 69 | a[key] = b[key]; 70 | } else { 71 | a[key] = objectExtend(a[key], b[key]); 72 | } 73 | } else { 74 | a[key] = b[key]; 75 | } 76 | }); 77 | 78 | return a; 79 | } 80 | 81 | /** 82 | * Assemble url from two segments 83 | * 84 | * @author Sahat Yalkabov 85 | * @copyright Method taken from https://github.com/sahat/satellizer 86 | * 87 | * @param {String} baseUrl Base url 88 | * @param {String} url URI 89 | * @return {String} 90 | */ 91 | function joinUrl(baseUrl, url) { 92 | if (/^(?:[a-z]+:)?\/\//i.test(url)) { 93 | return url; 94 | } 95 | let joined = [baseUrl, url].join('/'); 96 | let normalize = function (str) { 97 | return str 98 | .replace(/[\/]+/g, '/') 99 | .replace(/\/\?/g, '?') 100 | .replace(/\/\#/g, '#') 101 | .replace(/\:\//g, '://'); 102 | }; 103 | return normalize(joined); 104 | } 105 | 106 | /** 107 | * Get full path based on current location 108 | * 109 | * @author Sahat Yalkabov 110 | * @copyright Method taken from https://github.com/sahat/satellizer 111 | * 112 | * @param {Location} location 113 | * @return {String} 114 | */ 115 | function getFullUrlPath(location) { 116 | const isHttps = location.protocol === 'https:'; 117 | return ( 118 | location.protocol + 119 | '//' + 120 | location.hostname + 121 | ':' + 122 | (location.port || (isHttps ? '443' : '80')) + 123 | (/^\//.test(location.pathname) 124 | ? location.pathname 125 | : '/' + location.pathname) 126 | ); 127 | } 128 | 129 | /** 130 | * Parse query string variables 131 | * 132 | * @author Sahat Yalkabov 133 | * @copyright Method taken from https://github.com/sahat/satellizer 134 | * 135 | * @param {String} Query string 136 | * @return {String} 137 | */ 138 | function parseQueryString(str) { 139 | let obj = {}; 140 | let key; 141 | let value; 142 | (str || '').split('&').forEach(keyValue => { 143 | if (keyValue) { 144 | value = keyValue.split('='); 145 | key = decodeURIComponent(value[0]); 146 | obj[key] = !!value[1] ? decodeURIComponent(value[1]) : true; 147 | } 148 | }); 149 | return obj; 150 | } 151 | 152 | /** 153 | * Decode base64 string 154 | * @author Sahat Yalkabov 155 | * @copyright Method taken from https://github.com/sahat/satellizer 156 | * 157 | * @param {String} str base64 encoded string 158 | * @return {Object} 159 | */ 160 | function decodeBase64(str) { 161 | let buffer; 162 | if (typeof module !== 'undefined' && module.exports) { 163 | try { 164 | buffer = require('buffer').Buffer; 165 | } catch (err) { 166 | // noop 167 | } 168 | } 169 | 170 | let fromCharCode = String.fromCharCode; 171 | 172 | let re_btou = new RegExp( 173 | [ 174 | '[\xC0-\xDF][\x80-\xBF]', 175 | '[\xE0-\xEF][\x80-\xBF]{2}', 176 | '[\xF0-\xF7][\x80-\xBF]{3}', 177 | ].join('|'), 178 | 'g' 179 | ); 180 | 181 | let cb_btou = function (cccc) { 182 | switch (cccc.length) { 183 | case 4: 184 | let cp = 185 | ((0x07 & cccc.charCodeAt(0)) << 18) | 186 | ((0x3f & cccc.charCodeAt(1)) << 12) | 187 | ((0x3f & cccc.charCodeAt(2)) << 6) | 188 | (0x3f & cccc.charCodeAt(3)); 189 | let offset = cp - 0x10000; 190 | return ( 191 | fromCharCode((offset >>> 10) + 0xd800) + 192 | fromCharCode((offset & 0x3ff) + 0xdc00) 193 | ); 194 | case 3: 195 | return fromCharCode( 196 | ((0x0f & cccc.charCodeAt(0)) << 12) | 197 | ((0x3f & cccc.charCodeAt(1)) << 6) | 198 | (0x3f & cccc.charCodeAt(2)) 199 | ); 200 | default: 201 | return fromCharCode( 202 | ((0x1f & cccc.charCodeAt(0)) << 6) | (0x3f & cccc.charCodeAt(1)) 203 | ); 204 | } 205 | }; 206 | 207 | let btou = function (b) { 208 | return b.replace(re_btou, cb_btou); 209 | }; 210 | 211 | let _decode = buffer 212 | ? function (a) { 213 | return (a.constructor === buffer.constructor 214 | ? a 215 | : new buffer(a, 'base64') 216 | ).toString(); 217 | } 218 | : function (a) { 219 | return btou(atob(a)); 220 | }; 221 | 222 | return _decode( 223 | String(str) 224 | .replace(/[-_]/g, function (m0) { 225 | return m0 === '-' ? '+' : '/'; 226 | }) 227 | .replace(/[^A-Za-z0-9\+\/]/g, '') 228 | ); 229 | } 230 | 231 | function parseCookies(str = '') { 232 | if (str.length === 0) return {}; 233 | const parsed = {}; 234 | const pattern = new RegExp('\\s*;\\s*'); 235 | str.split(pattern).forEach(i => { 236 | const [encodedKey, encodedValue] = i.split('='); 237 | const key = decodeURIComponent(encodedKey); 238 | const value = decodeURIComponent(encodedValue); 239 | parsed[key] = value; 240 | }); 241 | return parsed; 242 | } 243 | 244 | function formatOptions(options) { 245 | const { path, domain, expires, secure } = options; 246 | return [ 247 | typeof path === 'undefined' || path === null ? '' : ';path=' + path, 248 | typeof domain === 'undefined' || domain === null ? '' : ';domain=' + domain, 249 | typeof expires === 'undefined' || expires === null 250 | ? '' 251 | : ';expires=' + expires.toUTCString(), 252 | typeof secure === 'undefined' || secure === null || secure === false 253 | ? '' 254 | : ';secure', 255 | ].join(''); 256 | } 257 | 258 | function formatCookie(key, value, options) { 259 | return [ 260 | encodeURIComponent(key), 261 | '=', 262 | encodeURIComponent(value), 263 | formatOptions(options), 264 | ].join(''); 265 | } 266 | 267 | function getObjectProperty(objectRef, propertyName) { 268 | let value = undefined; 269 | let valueRef = objectRef; 270 | const propNames = propertyName.split('.'); 271 | 272 | for (var i = 0; i < propNames.length; i++) { 273 | const key = propNames[i]; 274 | value = valueRef[key]; 275 | 276 | if (isObject(value)) { 277 | valueRef = valueRef[key]; 278 | } else { 279 | break; 280 | } 281 | } 282 | 283 | return value; 284 | } 285 | 286 | // Store setTimeout reference so promise-polyfill will be unaffected by 287 | // other code modifying setTimeout (like sinon.useFakeTimers()) 288 | var setTimeoutFunc = setTimeout; 289 | 290 | function noop() {} 291 | 292 | // Polyfill for Function.prototype.bind 293 | function bind(fn, thisArg) { 294 | return function () { 295 | fn.apply(thisArg, arguments); 296 | }; 297 | } 298 | 299 | function Promise$1(fn) { 300 | if (typeof this !== 'object') 301 | throw new TypeError('Promises must be constructed via new'); 302 | if (typeof fn !== 'function') throw new TypeError('not a function'); 303 | this._state = 0; 304 | this._handled = false; 305 | this._value = undefined; 306 | this._deferreds = []; 307 | 308 | doResolve(fn, this); 309 | } 310 | 311 | function handle(self, deferred) { 312 | while (self._state === 3) { 313 | self = self._value; 314 | } 315 | if (self._state === 0) { 316 | self._deferreds.push(deferred); 317 | return; 318 | } 319 | self._handled = true; 320 | Promise$1._immediateFn(function () { 321 | var cb = self._state === 1 ? deferred.onFulfilled : deferred.onRejected; 322 | if (cb === null) { 323 | (self._state === 1 ? resolve : reject)(deferred.promise, self._value); 324 | return; 325 | } 326 | var ret; 327 | try { 328 | ret = cb(self._value); 329 | } catch (e) { 330 | reject(deferred.promise, e); 331 | return; 332 | } 333 | resolve(deferred.promise, ret); 334 | }); 335 | } 336 | 337 | function resolve(self, newValue) { 338 | try { 339 | // Promise Resolution Procedure: https://github.com/promises-aplus/promises-spec#the-promise-resolution-procedure 340 | if (newValue === self) 341 | throw new TypeError('A promise cannot be resolved with itself.'); 342 | if ( 343 | newValue && 344 | (typeof newValue === 'object' || typeof newValue === 'function') 345 | ) { 346 | var then = newValue.then; 347 | if (newValue instanceof Promise$1) { 348 | self._state = 3; 349 | self._value = newValue; 350 | finale(self); 351 | return; 352 | } else if (typeof then === 'function') { 353 | doResolve(bind(then, newValue), self); 354 | return; 355 | } 356 | } 357 | self._state = 1; 358 | self._value = newValue; 359 | finale(self); 360 | } catch (e) { 361 | reject(self, e); 362 | } 363 | } 364 | 365 | function reject(self, newValue) { 366 | self._state = 2; 367 | self._value = newValue; 368 | finale(self); 369 | } 370 | 371 | function finale(self) { 372 | if (self._state === 2 && self._deferreds.length === 0) { 373 | Promise$1._immediateFn(function () { 374 | if (!self._handled) { 375 | Promise$1._unhandledRejectionFn(self._value); 376 | } 377 | }); 378 | } 379 | 380 | for (var i = 0, len = self._deferreds.length; i < len; i++) { 381 | handle(self, self._deferreds[i]); 382 | } 383 | self._deferreds = null; 384 | } 385 | 386 | function Handler(onFulfilled, onRejected, promise) { 387 | this.onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : null; 388 | this.onRejected = typeof onRejected === 'function' ? onRejected : null; 389 | this.promise = promise; 390 | } 391 | 392 | /** 393 | * Take a potentially misbehaving resolver function and make sure 394 | * onFulfilled and onRejected are only called once. 395 | * 396 | * Makes no guarantees about asynchrony. 397 | */ 398 | function doResolve(fn, self) { 399 | var done = false; 400 | try { 401 | fn( 402 | function (value) { 403 | if (done) return; 404 | done = true; 405 | resolve(self, value); 406 | }, 407 | function (reason) { 408 | if (done) return; 409 | done = true; 410 | reject(self, reason); 411 | } 412 | ); 413 | } catch (ex) { 414 | if (done) return; 415 | done = true; 416 | reject(self, ex); 417 | } 418 | } 419 | 420 | Promise$1.prototype['catch'] = function (onRejected) { 421 | return this.then(null, onRejected); 422 | }; 423 | 424 | Promise$1.prototype.then = function (onFulfilled, onRejected) { 425 | var prom = new this.constructor(noop); 426 | 427 | handle(this, new Handler(onFulfilled, onRejected, prom)); 428 | return prom; 429 | }; 430 | 431 | Promise$1.all = function (arr) { 432 | var args = Array.prototype.slice.call(arr); 433 | 434 | return new Promise$1(function (resolve, reject) { 435 | if (args.length === 0) return resolve([]); 436 | var remaining = args.length; 437 | 438 | function res(i, val) { 439 | try { 440 | if (val && (typeof val === 'object' || typeof val === 'function')) { 441 | var then = val.then; 442 | if (typeof then === 'function') { 443 | then.call( 444 | val, 445 | function (val) { 446 | res(i, val); 447 | }, 448 | reject 449 | ); 450 | return; 451 | } 452 | } 453 | args[i] = val; 454 | if (--remaining === 0) { 455 | resolve(args); 456 | } 457 | } catch (ex) { 458 | reject(ex); 459 | } 460 | } 461 | 462 | for (var i = 0; i < args.length; i++) { 463 | res(i, args[i]); 464 | } 465 | }); 466 | }; 467 | 468 | Promise$1.resolve = function (value) { 469 | if (value && typeof value === 'object' && value.constructor === Promise$1) { 470 | return value; 471 | } 472 | 473 | return new Promise$1(function (resolve) { 474 | resolve(value); 475 | }); 476 | }; 477 | 478 | Promise$1.reject = function (value) { 479 | return new Promise$1(function (resolve, reject) { 480 | reject(value); 481 | }); 482 | }; 483 | 484 | Promise$1.race = function (values) { 485 | return new Promise$1(function (resolve, reject) { 486 | for (var i = 0, len = values.length; i < len; i++) { 487 | values[i].then(resolve, reject); 488 | } 489 | }); 490 | }; 491 | 492 | // Use polyfill for setImmediate for performance gains 493 | Promise$1._immediateFn = 494 | (typeof setImmediate === 'function' && 495 | function (fn) { 496 | setImmediate(fn); 497 | }) || 498 | function (fn) { 499 | setTimeoutFunc(fn, 0); 500 | }; 501 | 502 | Promise$1._unhandledRejectionFn = function _unhandledRejectionFn(err) { 503 | if (typeof console !== 'undefined' && console) { 504 | console.warn('Possible Unhandled Promise Rejection:', err); // eslint-disable-line no-console 505 | } 506 | }; 507 | 508 | /** 509 | * Set the immediate function to execute callbacks 510 | * @param fn {function} Function to execute 511 | * @deprecated 512 | */ 513 | Promise$1._setImmediateFn = function _setImmediateFn(fn) { 514 | Promise$1._immediateFn = fn; 515 | }; 516 | 517 | /** 518 | * Change the function to execute on unhandled rejection 519 | * @param {function} fn Function to execute on unhandled rejection 520 | * @deprecated 521 | */ 522 | Promise$1._setUnhandledRejectionFn = function _setUnhandledRejectionFn(fn) { 523 | Promise$1._unhandledRejectionFn = fn; 524 | }; 525 | 526 | const fakeDocument = { 527 | createElement() { }, 528 | }; 529 | 530 | const fakeWindow = { 531 | atob() { }, 532 | open() { }, 533 | location: {}, 534 | localStorage: { 535 | setItem() { }, 536 | getItem() { }, 537 | removeItem() { }, 538 | }, 539 | sessionStorage: { 540 | setItem() { }, 541 | getItem() { }, 542 | removeItem() { }, 543 | }, 544 | }; 545 | 546 | const $document = (typeof document !== undefined) 547 | ? document 548 | : fakeDocument; 549 | 550 | const $window = (typeof window !== undefined) 551 | ? window 552 | : fakeWindow; 553 | 554 | function getCookieDomainUrl() { 555 | try { 556 | return $window.location.hostname; 557 | } catch (e) {} 558 | 559 | return ''; 560 | } 561 | 562 | function getRedirectUri(uri) { 563 | try { 564 | return !isUndefined(uri) 565 | ? `${$window.location.origin}${uri}` 566 | : $window.location.origin; 567 | } catch (e) {} 568 | 569 | return uri || null; 570 | } 571 | 572 | /** 573 | * Default configuration 574 | */ 575 | var defaultOptions = { 576 | baseUrl: null, 577 | tokenPath: 'access_token', 578 | tokenName: 'token', 579 | tokenPrefix: 'vueauth', 580 | tokenHeader: 'Authorization', 581 | tokenType: 'Bearer', 582 | loginUrl: '/auth/login', 583 | registerUrl: '/auth/register', 584 | logoutUrl: null, 585 | storageType: 'localStorage', 586 | storageNamespace: 'vue-authenticate', 587 | cookieStorage: { 588 | domain: getCookieDomainUrl(), 589 | path: '/', 590 | secure: false, 591 | }, 592 | requestDataKey: 'data', 593 | responseDataKey: 'data', 594 | 595 | /** 596 | * Default request interceptor for Axios library 597 | * @context {VueAuthenticate} 598 | */ 599 | bindRequestInterceptor: function ($auth) { 600 | const tokenHeader = $auth.options.tokenHeader; 601 | 602 | $auth.$http.interceptors.request.use(config => { 603 | if ($auth.isAuthenticated()) { 604 | config.headers[tokenHeader] = [ 605 | $auth.options.tokenType, 606 | $auth.getToken(), 607 | ].join(' '); 608 | } else { 609 | delete config.headers[tokenHeader]; 610 | } 611 | return config; 612 | }); 613 | }, 614 | 615 | providers: { 616 | facebook: { 617 | name: 'facebook', 618 | url: '/auth/facebook', 619 | authorizationEndpoint: 'https://www.facebook.com/v10.0/dialog/oauth', 620 | redirectUri: getRedirectUri('/'), 621 | requiredUrlParams: ['display', 'scope'], 622 | scope: ['email'], 623 | scopeDelimiter: ',', 624 | display: 'popup', 625 | oauthType: '2.0', 626 | popupOptions: { width: 580, height: 400 }, 627 | }, 628 | 629 | google: { 630 | name: 'google', 631 | url: '/auth/google', 632 | authorizationEndpoint: 'https://accounts.google.com/o/oauth2/auth', 633 | redirectUri: getRedirectUri(), 634 | requiredUrlParams: ['scope'], 635 | optionalUrlParams: ['display'], 636 | scope: ['profile', 'email'], 637 | scopePrefix: 'openid', 638 | scopeDelimiter: ' ', 639 | display: 'popup', 640 | oauthType: '2.0', 641 | popupOptions: { width: 452, height: 633 }, 642 | }, 643 | 644 | github: { 645 | name: 'github', 646 | url: '/auth/github', 647 | authorizationEndpoint: 'https://github.com/login/oauth/authorize', 648 | redirectUri: getRedirectUri(), 649 | optionalUrlParams: ['scope'], 650 | scope: ['user:email'], 651 | scopeDelimiter: ' ', 652 | oauthType: '2.0', 653 | popupOptions: { width: 1020, height: 618 }, 654 | }, 655 | 656 | instagram: { 657 | name: 'instagram', 658 | url: '/auth/instagram', 659 | authorizationEndpoint: 'https://api.instagram.com/oauth/authorize', 660 | redirectUri: getRedirectUri(), 661 | requiredUrlParams: ['scope'], 662 | scope: ['basic'], 663 | scopeDelimiter: '+', 664 | oauthType: '2.0', 665 | popupOptions: { width: null, height: null }, 666 | }, 667 | 668 | twitter: { 669 | name: 'twitter', 670 | url: '/auth/twitter', 671 | authorizationEndpoint: 'https://api.twitter.com/oauth/authenticate', 672 | redirectUri: getRedirectUri(), 673 | oauthType: '1.0', 674 | popupOptions: { width: 495, height: 645 }, 675 | }, 676 | 677 | bitbucket: { 678 | name: 'bitbucket', 679 | url: '/auth/bitbucket', 680 | authorizationEndpoint: 'https://bitbucket.org/site/oauth2/authorize', 681 | redirectUri: getRedirectUri('/'), 682 | optionalUrlParams: ['scope'], 683 | scope: ['email'], 684 | scopeDelimiter: ' ', 685 | oauthType: '2.0', 686 | popupOptions: { width: 1020, height: 618 }, 687 | }, 688 | 689 | linkedin: { 690 | name: 'linkedin', 691 | url: '/auth/linkedin', 692 | authorizationEndpoint: 'https://www.linkedin.com/oauth/v2/authorization', 693 | redirectUri: getRedirectUri(), 694 | requiredUrlParams: ['state'], 695 | scope: ['r_emailaddress'], 696 | scopeDelimiter: ' ', 697 | state: 'STATE', 698 | oauthType: '2.0', 699 | popupOptions: { width: 527, height: 582 }, 700 | }, 701 | 702 | live: { 703 | name: 'live', 704 | url: '/auth/live', 705 | authorizationEndpoint: 'https://login.live.com/oauth20_authorize.srf', 706 | redirectUri: getRedirectUri(), 707 | requiredUrlParams: ['display', 'scope'], 708 | scope: ['wl.emails'], 709 | scopeDelimiter: ' ', 710 | display: 'popup', 711 | oauthType: '2.0', 712 | popupOptions: { width: 500, height: 560 }, 713 | }, 714 | 715 | oauth1: { 716 | name: null, 717 | url: '/auth/oauth1', 718 | authorizationEndpoint: null, 719 | redirectUri: getRedirectUri(), 720 | oauthType: '1.0', 721 | popupOptions: null, 722 | }, 723 | 724 | oauth2: { 725 | name: null, 726 | url: '/auth/oauth2', 727 | clientId: null, 728 | redirectUri: getRedirectUri(), 729 | authorizationEndpoint: null, 730 | defaultUrlParams: ['response_type', 'client_id', 'redirect_uri'], 731 | requiredUrlParams: null, 732 | optionalUrlParams: null, 733 | scope: null, 734 | scopePrefix: null, 735 | scopeDelimiter: null, 736 | state: null, 737 | oauthType: '2.0', 738 | popupOptions: null, 739 | responseType: 'code', 740 | responseParams: { 741 | code: 'code', 742 | clientId: 'clientId', 743 | redirectUri: 'redirectUri', 744 | }, 745 | }, 746 | }, 747 | }; 748 | 749 | class CookieStorage { 750 | constructor(defaultOptions) { 751 | this._defaultOptions = objectExtend( 752 | { 753 | domain: getCookieDomainUrl(), 754 | expires: null, 755 | path: '/', 756 | secure: false, 757 | }, 758 | defaultOptions 759 | ); 760 | } 761 | 762 | setItem(key, value) { 763 | const options = objectExtend({}, this._defaultOptions); 764 | const cookie = formatCookie(key, value, options); 765 | this._setCookie(cookie); 766 | } 767 | 768 | getItem(key) { 769 | const cookies = parseCookies(this._getCookie()); 770 | return cookies.hasOwnProperty(key) ? cookies[key] : null; 771 | } 772 | 773 | removeItem(key) { 774 | const value = ''; 775 | const defaultOptions = objectExtend({}, this._defaultOptions); 776 | const options = objectExtend(defaultOptions, { 777 | expires: new Date(0), 778 | }); 779 | const cookie = formatCookie(key, value, options); 780 | this._setCookie(cookie); 781 | } 782 | 783 | _getCookie() { 784 | try { 785 | return $document.cookie === 'undefined' ? '' : $document.cookie; 786 | } catch (e) {} 787 | 788 | return ''; 789 | } 790 | 791 | _setCookie(cookie) { 792 | try { 793 | $document.cookie = cookie; 794 | } catch (e) {} 795 | } 796 | } 797 | 798 | class LocalStorage { 799 | constructor(namespace) { 800 | this.namespace = namespace || null; 801 | } 802 | 803 | setItem(key, value) { 804 | $window.localStorage.setItem(this._getStorageKey(key), value); 805 | } 806 | 807 | getItem(key) { 808 | return $window.localStorage.getItem(this._getStorageKey(key)); 809 | } 810 | 811 | removeItem(key) { 812 | $window.localStorage.removeItem(this._getStorageKey(key)); 813 | } 814 | 815 | _getStorageKey(key) { 816 | if (this.namespace) { 817 | return [this.namespace, key].join('.'); 818 | } 819 | return key; 820 | } 821 | } 822 | 823 | class MemoryStorage { 824 | constructor(namespace) { 825 | this.namespace = namespace || null; 826 | this._storage = {}; 827 | } 828 | 829 | setItem(key, value) { 830 | this._storage[this._getStorageKey(key)] = value; 831 | } 832 | 833 | getItem(key) { 834 | return this._storage[this._getStorageKey(key)]; 835 | } 836 | 837 | removeItem(key) { 838 | delete this._storage[this._getStorageKey(key)]; 839 | } 840 | 841 | _getStorageKey(key) { 842 | if (this.namespace) { 843 | return [this.namespace, key].join('.'); 844 | } 845 | return key; 846 | } 847 | } 848 | 849 | class SessionStorage { 850 | constructor(namespace) { 851 | this.namespace = namespace || null; 852 | } 853 | 854 | setItem(key, value) { 855 | $window.sessionStorage.setItem(this._getStorageKey(key), value); 856 | } 857 | 858 | getItem(key) { 859 | return $window.sessionStorage.getItem(this._getStorageKey(key)); 860 | } 861 | 862 | removeItem(key) { 863 | $window.sessionStorage.removeItem(this._getStorageKey(key)); 864 | } 865 | 866 | _getStorageKey(key) { 867 | if (this.namespace) { 868 | return [this.namespace, key].join('.'); 869 | } 870 | return key; 871 | } 872 | } 873 | 874 | function StorageFactory(options) { 875 | switch (options.storageType) { 876 | case 'localStorage': 877 | try { 878 | $window.localStorage.setItem('testKey', 'test'); 879 | $window.localStorage.removeItem('testKey'); 880 | return new LocalStorage(options.storageNamespace); 881 | } catch (e) {} 882 | 883 | case 'sessionStorage': 884 | try { 885 | $window.sessionStorage.setItem('testKey', 'test'); 886 | $window.sessionStorage.removeItem('testKey'); 887 | return new SessionStorage(options.storageNamespace); 888 | } catch (e) {} 889 | 890 | case 'cookieStorage': 891 | return new CookieStorage(options.cookieStorage); 892 | 893 | case 'memoryStorage': 894 | default: 895 | return new MemoryStorage(options.storageNamespace); 896 | } 897 | } 898 | 899 | /** 900 | * OAuth2 popup management class 901 | * 902 | * @author Sahat Yalkabov 903 | * @copyright Class mostly taken from https://github.com/sahat/satellizer 904 | * and adjusted to fit vue-authenticate library 905 | */ 906 | class OAuthPopup { 907 | constructor(url, name, popupOptions) { 908 | this.popup = null; 909 | this.url = url; 910 | this.name = name; 911 | this.popupOptions = popupOptions; 912 | } 913 | 914 | open(redirectUri, skipPooling) { 915 | try { 916 | this.popup = $window.open(this.url, this.name, this._stringifyOptions()); 917 | if (this.popup && this.popup.focus) { 918 | this.popup.focus(); 919 | } 920 | 921 | if (skipPooling) { 922 | return Promise$1.resolve(); 923 | } else { 924 | return this.pooling(redirectUri); 925 | } 926 | } catch (e) { 927 | return Promise$1.reject(new Error('OAuth popup error occurred')); 928 | } 929 | } 930 | 931 | pooling(redirectUri) { 932 | return new Promise$1((resolve, reject) => { 933 | const redirectUriParser = $document.createElement('a'); 934 | redirectUriParser.href = redirectUri; 935 | const redirectUriPath = getFullUrlPath(redirectUriParser); 936 | 937 | let poolingInterval = setInterval(() => { 938 | if ( 939 | !this.popup || 940 | this.popup.closed || 941 | this.popup.closed === undefined 942 | ) { 943 | clearInterval(poolingInterval); 944 | poolingInterval = null; 945 | reject(new Error('Auth popup window closed')); 946 | } 947 | 948 | try { 949 | const popupWindowPath = getFullUrlPath(this.popup.location); 950 | 951 | if (popupWindowPath === redirectUriPath) { 952 | if (this.popup.location.search || this.popup.location.hash) { 953 | const query = parseQueryString( 954 | this.popup.location.search.substring(1).replace(/\/$/, '') 955 | ); 956 | const hash = parseQueryString( 957 | this.popup.location.hash.substring(1).replace(/[\/$]/, '') 958 | ); 959 | let params = objectExtend({}, query); 960 | params = objectExtend(params, hash); 961 | 962 | if (params.error) { 963 | reject(new Error(params.error)); 964 | } else { 965 | resolve(params); 966 | } 967 | } else { 968 | reject( 969 | new Error( 970 | 'OAuth redirect has occurred but no query or hash parameters were found.' 971 | ) 972 | ); 973 | } 974 | 975 | clearInterval(poolingInterval); 976 | poolingInterval = null; 977 | this.popup.close(); 978 | } 979 | } catch (e) { 980 | // Ignore DOMException: Blocked a frame with origin from accessing a cross-origin frame. 981 | } 982 | }, 250); 983 | }); 984 | } 985 | 986 | _stringifyOptions() { 987 | let options = []; 988 | for (var optionKey in this.popupOptions) { 989 | if (!isUndefined(this.popupOptions[optionKey])) { 990 | options.push(`${optionKey}=${this.popupOptions[optionKey]}`); 991 | } 992 | } 993 | return options.join(','); 994 | } 995 | } 996 | 997 | const defaultProviderConfig$1 = { 998 | name: null, 999 | url: null, 1000 | authorizationEndpoint: null, 1001 | scope: null, 1002 | scopePrefix: null, 1003 | scopeDelimiter: null, 1004 | redirectUri: null, 1005 | requiredUrlParams: null, 1006 | defaultUrlParams: null, 1007 | oauthType: '1.0', 1008 | popupOptions: {}, 1009 | }; 1010 | 1011 | class OAuth { 1012 | constructor($http, storage, providerConfig, options) { 1013 | this.$http = $http; 1014 | this.storage = storage; 1015 | this.providerConfig = objectExtend({}, defaultProviderConfig$1); 1016 | this.providerConfig = objectExtend(this.providerConfig, providerConfig); 1017 | this.options = options; 1018 | } 1019 | 1020 | /** 1021 | * Initialize OAuth1 process 1022 | * @param {Object} userData User data 1023 | * @return {Promise} 1024 | */ 1025 | init(userData) { 1026 | this.oauthPopup = new OAuthPopup( 1027 | 'about:blank', 1028 | this.providerConfig.name, 1029 | this.providerConfig.popupOptions 1030 | ); 1031 | 1032 | if (!$window['cordova']) { 1033 | this.oauthPopup.open(this.providerConfig.redirectUri, true); 1034 | } 1035 | 1036 | return this.getRequestToken().then(response => { 1037 | return this.openPopup(response).then(popupResponse => { 1038 | return this.exchangeForToken(popupResponse, userData); 1039 | }); 1040 | }); 1041 | } 1042 | 1043 | /** 1044 | * Get OAuth1 request token 1045 | * @return {Promise} 1046 | */ 1047 | getRequestToken() { 1048 | let requestOptions = {}; 1049 | requestOptions.method = 'POST'; 1050 | requestOptions[this.options.requestDataKey] = objectExtend( 1051 | {}, 1052 | this.providerConfig 1053 | ); 1054 | requestOptions.withCredentials = this.options.withCredentials; 1055 | if (this.options.baseUrl) { 1056 | requestOptions.url = joinUrl( 1057 | this.options.baseUrl, 1058 | this.providerConfig.url 1059 | ); 1060 | } else { 1061 | requestOptions.url = this.providerConfig.url; 1062 | } 1063 | 1064 | return this.$http(requestOptions); 1065 | } 1066 | 1067 | /** 1068 | * Open OAuth1 popup 1069 | * @param {Object} response Response object containing request token 1070 | * @return {Promise} 1071 | */ 1072 | openPopup(response) { 1073 | const url = [ 1074 | this.providerConfig.authorizationEndpoint, 1075 | this.buildQueryString(response[this.options.responseDataKey]), 1076 | ].join('?'); 1077 | 1078 | this.oauthPopup.popup.location = url; 1079 | if ($window['cordova']) { 1080 | return this.oauthPopup.open(this.providerConfig.redirectUri); 1081 | } else { 1082 | return this.oauthPopup.pooling(this.providerConfig.redirectUri); 1083 | } 1084 | } 1085 | 1086 | /** 1087 | * Exchange token and token verifier for access token 1088 | * @param {Object} oauth OAuth data containing token and token verifier 1089 | * @param {Object} userData User data 1090 | * @return {Promise} 1091 | */ 1092 | exchangeForToken(oauth, userData) { 1093 | let payload = objectExtend({}, userData); 1094 | payload = objectExtend(payload, oauth); 1095 | let requestOptions = {}; 1096 | requestOptions.method = 'POST'; 1097 | requestOptions[this.options.requestDataKey] = payload; 1098 | requestOptions.withCredentials = this.options.withCredentials; 1099 | if (this.options.baseUrl) { 1100 | requestOptions.url = joinUrl( 1101 | this.options.baseUrl, 1102 | this.providerConfig.url 1103 | ); 1104 | } else { 1105 | requestOptions.url = this.providerConfig.url; 1106 | } 1107 | return this.$http(requestOptions); 1108 | } 1109 | 1110 | buildQueryString(params) { 1111 | const parsedParams = []; 1112 | for (var key in params) { 1113 | let value = params[key]; 1114 | parsedParams.push( 1115 | encodeURIComponent(key) + '=' + encodeURIComponent(value) 1116 | ); 1117 | } 1118 | return parsedParams.join('&'); 1119 | } 1120 | } 1121 | 1122 | /** 1123 | * Default provider configuration 1124 | * @type {Object} 1125 | */ 1126 | const defaultProviderConfig = { 1127 | name: null, 1128 | url: null, 1129 | clientId: null, 1130 | authorizationEndpoint: null, 1131 | redirectUri: null, 1132 | scope: null, 1133 | scopePrefix: null, 1134 | scopeDelimiter: null, 1135 | state: null, 1136 | requiredUrlParams: null, 1137 | defaultUrlParams: ['response_type', 'client_id', 'redirect_uri'], 1138 | responseType: 'code', 1139 | responseParams: { 1140 | code: 'code', 1141 | clientId: 'clientId', 1142 | redirectUri: 'redirectUri', 1143 | }, 1144 | oauthType: '2.0', 1145 | popupOptions: {}, 1146 | }; 1147 | 1148 | class OAuth2 { 1149 | constructor($http, storage, providerConfig, options) { 1150 | this.$http = $http; 1151 | this.storage = storage; 1152 | this.providerConfig = objectExtend({}, defaultProviderConfig); 1153 | this.providerConfig = objectExtend(this.providerConfig, providerConfig); 1154 | this.options = options; 1155 | } 1156 | 1157 | init(userData) { 1158 | let stateName = this.providerConfig.name + '_state'; 1159 | if (isFunction(this.providerConfig.state)) { 1160 | this.storage.setItem(stateName, this.providerConfig.state()); 1161 | } else if (isString(this.providerConfig.state)) { 1162 | this.storage.setItem(stateName, this.providerConfig.state); 1163 | } 1164 | 1165 | let url = [ 1166 | this.providerConfig.authorizationEndpoint, 1167 | this._stringifyRequestParams(), 1168 | ].join('?'); 1169 | 1170 | this.oauthPopup = new OAuthPopup( 1171 | url, 1172 | this.providerConfig.name, 1173 | this.providerConfig.popupOptions 1174 | ); 1175 | 1176 | return new Promise((resolve, reject) => { 1177 | this.oauthPopup 1178 | .open(this.providerConfig.redirectUri) 1179 | .then(response => { 1180 | if ( 1181 | this.providerConfig.responseType === 'token' || 1182 | !this.providerConfig.url 1183 | ) { 1184 | return resolve(response); 1185 | } 1186 | 1187 | if ( 1188 | response.state && 1189 | response.state !== this.storage.getItem(stateName) 1190 | ) { 1191 | return reject( 1192 | new Error( 1193 | 'State parameter value does not match original OAuth request state value' 1194 | ) 1195 | ); 1196 | } 1197 | 1198 | resolve(this.exchangeForToken(response, userData)); 1199 | }) 1200 | .catch(err => { 1201 | reject(err); 1202 | }); 1203 | }); 1204 | } 1205 | 1206 | /** 1207 | * Exchange temporary oauth data for access token 1208 | * @author Sahat Yalkabov 1209 | * @copyright Method taken from https://github.com/sahat/satellizer 1210 | * 1211 | * @param {[type]} oauth [description] 1212 | * @param {[type]} userData [description] 1213 | * @return {[type]} [description] 1214 | */ 1215 | exchangeForToken(oauth, userData) { 1216 | let payload = objectExtend({}, userData); 1217 | 1218 | for (let key in this.providerConfig.responseParams) { 1219 | this.providerConfig.responseParams[key]; 1220 | 1221 | switch (key) { 1222 | case 'code': 1223 | payload[key] = oauth.code; 1224 | break; 1225 | case 'clientId': 1226 | payload[key] = this.providerConfig.clientId; 1227 | break; 1228 | case 'redirectUri': 1229 | payload[key] = this.providerConfig.redirectUri; 1230 | break; 1231 | default: 1232 | payload[key] = oauth[key]; 1233 | } 1234 | } 1235 | 1236 | if (oauth.state) { 1237 | payload.state = oauth.state; 1238 | } 1239 | 1240 | let exchangeTokenUrl; 1241 | if (this.options.baseUrl) { 1242 | exchangeTokenUrl = joinUrl(this.options.baseUrl, this.providerConfig.url); 1243 | } else { 1244 | exchangeTokenUrl = this.providerConfig.url; 1245 | } 1246 | 1247 | return this.$http.post(exchangeTokenUrl, payload, { 1248 | withCredentials: this.options.withCredentials, 1249 | }); 1250 | } 1251 | 1252 | /** 1253 | * Stringify oauth params 1254 | * @author Sahat Yalkabov 1255 | * @copyright Method taken from https://github.com/sahat/satellizer 1256 | * 1257 | * @return {String} 1258 | */ 1259 | _stringifyRequestParams() { 1260 | let keyValuePairs = []; 1261 | let paramCategories = [ 1262 | 'defaultUrlParams', 1263 | 'requiredUrlParams', 1264 | 'optionalUrlParams', 1265 | ]; 1266 | 1267 | paramCategories.forEach(categoryName => { 1268 | if (!this.providerConfig[categoryName]) return; 1269 | if (!Array.isArray(this.providerConfig[categoryName])) return; 1270 | 1271 | this.providerConfig[categoryName].forEach(paramName => { 1272 | let camelCaseParamName = camelCase(paramName); 1273 | let paramValue = isFunction(this.providerConfig[paramName]) 1274 | ? this.providerConfig[paramName]() 1275 | : this.providerConfig[camelCaseParamName]; 1276 | 1277 | if (paramName === 'redirect_uri' && !paramValue) return; 1278 | 1279 | if (paramName === 'state') { 1280 | let stateName = this.providerConfig.name + '_state'; 1281 | paramValue = encodeURIComponent(this.storage.getItem(stateName)); 1282 | } 1283 | if (paramName === 'scope' && Array.isArray(paramValue)) { 1284 | paramValue = paramValue.join(this.providerConfig.scopeDelimiter); 1285 | if (this.providerConfig.scopePrefix) { 1286 | paramValue = [this.providerConfig.scopePrefix, paramValue].join( 1287 | this.providerConfig.scopeDelimiter 1288 | ); 1289 | } 1290 | } 1291 | 1292 | keyValuePairs.push([paramName, paramValue]); 1293 | }); 1294 | }); 1295 | 1296 | return keyValuePairs 1297 | .map(param => { 1298 | return param.join('='); 1299 | }) 1300 | .join('&'); 1301 | } 1302 | } 1303 | 1304 | class VueAuthenticate { 1305 | constructor($http, overrideOptions) { 1306 | let options = objectExtend({}, defaultOptions); 1307 | options = objectExtend(options, overrideOptions); 1308 | let storage = StorageFactory(options); 1309 | 1310 | Object.defineProperties(this, { 1311 | $http: { 1312 | get() { 1313 | return $http; 1314 | }, 1315 | }, 1316 | 1317 | options: { 1318 | get() { 1319 | return options; 1320 | }, 1321 | }, 1322 | 1323 | storage: { 1324 | get() { 1325 | return storage; 1326 | }, 1327 | }, 1328 | 1329 | tokenName: { 1330 | get() { 1331 | if (this.options.tokenPrefix) { 1332 | return [this.options.tokenPrefix, this.options.tokenName].join('_'); 1333 | } else { 1334 | return this.options.tokenName; 1335 | } 1336 | }, 1337 | }, 1338 | }); 1339 | 1340 | // Setup request interceptors 1341 | if ( 1342 | this.options.bindRequestInterceptor && 1343 | isFunction(this.options.bindRequestInterceptor) 1344 | ) { 1345 | this.options.bindRequestInterceptor.call(this, this); 1346 | } else { 1347 | throw new Error('Request interceptor must be functions'); 1348 | } 1349 | } 1350 | 1351 | /** 1352 | * Check if user is authenticated 1353 | * @author Sahat Yalkabov 1354 | * @copyright Method taken from https://github.com/sahat/satellizer 1355 | * @return {Boolean} 1356 | */ 1357 | isAuthenticated() { 1358 | let token = this.storage.getItem(this.tokenName); 1359 | 1360 | if (token) { 1361 | // Token is present 1362 | if (token.split('.').length === 3) { 1363 | // Token with a valid JWT format XXX.YYY.ZZZ 1364 | try { 1365 | // Could be a valid JWT or an access token with the same format 1366 | const base64Url = token.split('.')[1]; 1367 | const base64 = base64Url.replace('-', '+').replace('_', '/'); 1368 | const exp = JSON.parse($window.atob(base64)).exp; 1369 | if (typeof exp === 'number') { 1370 | // JWT with an optonal expiration claims 1371 | return Math.round(new Date().getTime() / 1000) < exp; 1372 | } 1373 | } catch (e) { 1374 | return true; // Pass: Non-JWT token that looks like JWT 1375 | } 1376 | } 1377 | return true; // Pass: All other tokens 1378 | } 1379 | return false; 1380 | } 1381 | 1382 | /** 1383 | * Get token if user is authenticated 1384 | * @return {String} Authentication token 1385 | */ 1386 | getToken() { 1387 | return this.storage.getItem(this.tokenName); 1388 | } 1389 | 1390 | /** 1391 | * Set new authentication token 1392 | * @param {String|Object} token 1393 | */ 1394 | setToken(response, tokenPath) { 1395 | if (response[this.options.responseDataKey]) { 1396 | response = response[this.options.responseDataKey]; 1397 | } 1398 | 1399 | const responseTokenPath = tokenPath || this.options.tokenPath; 1400 | const token = getObjectProperty(response, responseTokenPath); 1401 | 1402 | if (token) { 1403 | this.storage.setItem(this.tokenName, token); 1404 | } 1405 | } 1406 | 1407 | getPayload() { 1408 | const token = this.storage.getItem(this.tokenName); 1409 | 1410 | if (token && token.split('.').length === 3) { 1411 | try { 1412 | const base64Url = token.split('.')[1]; 1413 | const base64 = base64Url.replace('-', '+').replace('_', '/'); 1414 | return JSON.parse(decodeBase64(base64)); 1415 | } catch (e) {} 1416 | } 1417 | } 1418 | 1419 | /** 1420 | * Login user using email and password 1421 | * @param {Object} user User data 1422 | * @param {Object} requestOptions Request options 1423 | * @return {Promise} Request promise 1424 | */ 1425 | login(user, requestOptions) { 1426 | requestOptions = requestOptions || {}; 1427 | requestOptions.url = requestOptions.url 1428 | ? requestOptions.url 1429 | : joinUrl(this.options.baseUrl, this.options.loginUrl); 1430 | requestOptions[this.options.requestDataKey] = 1431 | user || requestOptions[this.options.requestDataKey]; 1432 | requestOptions.method = requestOptions.method || 'POST'; 1433 | requestOptions.withCredentials = 1434 | requestOptions.withCredentials || this.options.withCredentials; 1435 | 1436 | return this.$http(requestOptions).then(response => { 1437 | this.setToken(response); 1438 | return response; 1439 | }); 1440 | } 1441 | 1442 | /** 1443 | * Register new user 1444 | * @param {Object} user User data 1445 | * @param {Object} requestOptions Request options 1446 | * @return {Promise} Request promise 1447 | */ 1448 | register(user, requestOptions) { 1449 | requestOptions = requestOptions || {}; 1450 | requestOptions.url = requestOptions.url 1451 | ? requestOptions.url 1452 | : joinUrl(this.options.baseUrl, this.options.registerUrl); 1453 | requestOptions[this.options.requestDataKey] = 1454 | user || requestOptions[this.options.requestDataKey]; 1455 | requestOptions.method = requestOptions.method || 'POST'; 1456 | requestOptions.withCredentials = 1457 | requestOptions.withCredentials || this.options.withCredentials; 1458 | 1459 | return this.$http(requestOptions).then(response => { 1460 | this.setToken(response); 1461 | return response; 1462 | }); 1463 | } 1464 | 1465 | /** 1466 | * Logout current user 1467 | * @param {Object} requestOptions Logout request options object 1468 | * @return {Promise} Request promise 1469 | */ 1470 | logout(requestOptions) { 1471 | if (!this.isAuthenticated()) { 1472 | return Promise$1.reject( 1473 | new Error('There is no currently authenticated user') 1474 | ); 1475 | } 1476 | 1477 | requestOptions = requestOptions || {}; 1478 | 1479 | if (requestOptions.url || this.options.logoutUrl) { 1480 | requestOptions.url = requestOptions.url 1481 | ? requestOptions.url 1482 | : joinUrl(this.options.baseUrl, this.options.logoutUrl); 1483 | requestOptions.method = requestOptions.method || 'POST'; 1484 | requestOptions[this.options.requestDataKey] = 1485 | requestOptions[this.options.requestDataKey] || undefined; 1486 | requestOptions.withCredentials = 1487 | requestOptions.withCredentials || this.options.withCredentials; 1488 | 1489 | return this.$http(requestOptions).then(response => { 1490 | this.storage.removeItem(this.tokenName); 1491 | return response; 1492 | }); 1493 | } else { 1494 | this.storage.removeItem(this.tokenName); 1495 | return Promise$1.resolve(); 1496 | } 1497 | } 1498 | 1499 | /** 1500 | * Authenticate user using authentication provider 1501 | * 1502 | * @param {String} provider Provider name 1503 | * @param {Object} userData User data 1504 | * @return {Promise} Request promise 1505 | */ 1506 | authenticate(provider, userData) { 1507 | return new Promise$1((resolve, reject) => { 1508 | var providerConfig = this.options.providers[provider]; 1509 | if (!providerConfig) { 1510 | return reject(new Error('Unknown provider')); 1511 | } 1512 | 1513 | let providerInstance; 1514 | switch (providerConfig.oauthType) { 1515 | case '1.0': 1516 | providerInstance = new OAuth( 1517 | this.$http, 1518 | this.storage, 1519 | providerConfig, 1520 | this.options 1521 | ); 1522 | break; 1523 | case '2.0': 1524 | providerInstance = new OAuth2( 1525 | this.$http, 1526 | this.storage, 1527 | providerConfig, 1528 | this.options 1529 | ); 1530 | break; 1531 | default: 1532 | return reject(new Error('Invalid OAuth type')); 1533 | } 1534 | 1535 | return providerInstance 1536 | .init(userData) 1537 | .then(response => { 1538 | this.setToken(response, providerConfig.tokenPath); 1539 | 1540 | if (this.isAuthenticated()) { 1541 | return resolve(response); 1542 | } else { 1543 | return reject(new Error('Authentication failed')); 1544 | } 1545 | }) 1546 | .catch(err => reject(err)); 1547 | }); 1548 | } 1549 | 1550 | /** 1551 | * Link user using authentication provider without login 1552 | * 1553 | * @param {String} provider Provider name 1554 | * @param {Object} userData User data 1555 | * @return {Promise} Request promise 1556 | */ 1557 | link(provider, userData) { 1558 | return new Promise$1((resolve, reject) => { 1559 | var providerConfig = this.options.providers[provider]; 1560 | if (!providerConfig) { 1561 | return reject(new Error('Unknown provider')); 1562 | } 1563 | 1564 | let providerInstance; 1565 | switch (providerConfig.oauthType) { 1566 | case '1.0': 1567 | providerInstance = new OAuth( 1568 | this.$http, 1569 | this.storage, 1570 | providerConfig, 1571 | this.options 1572 | ); 1573 | break; 1574 | case '2.0': 1575 | providerInstance = new OAuth2( 1576 | this.$http, 1577 | this.storage, 1578 | providerConfig, 1579 | this.options 1580 | ); 1581 | break; 1582 | default: 1583 | return reject(new Error('Invalid OAuth type')); 1584 | } 1585 | 1586 | return providerInstance 1587 | .init(userData) 1588 | .then(response => { 1589 | if (response[this.options.responseDataKey]) { 1590 | response = response[this.options.responseDataKey]; 1591 | } 1592 | 1593 | resolve(response); 1594 | }) 1595 | .catch(reject); 1596 | }); 1597 | } 1598 | } 1599 | 1600 | /** 1601 | * VueAuthenticate plugin 1602 | * @param {Object} Vue 1603 | * @param {Object} options 1604 | */ 1605 | function plugin(Vue, options) { 1606 | if (plugin.installed) { 1607 | return; 1608 | } 1609 | 1610 | plugin.installed = true; 1611 | 1612 | let vueAuthInstance = null; 1613 | Object.defineProperties(Vue.prototype, { 1614 | $auth: { 1615 | get() { 1616 | if (!vueAuthInstance) { 1617 | // Request handler library not found, throw error 1618 | if (!this.$http) { 1619 | throw new Error('Request handler instance not found'); 1620 | } 1621 | 1622 | vueAuthInstance = new VueAuthenticate(this.$http, options); 1623 | } 1624 | return vueAuthInstance; 1625 | }, 1626 | }, 1627 | }); 1628 | } 1629 | 1630 | /** 1631 | * External factory helper for ES5 and CommonJS 1632 | * @param {Object} $http Instance of request handling library 1633 | * @param {Object} options Configuration object 1634 | * @return {VueAuthenticate} VueAuthenticate instance 1635 | */ 1636 | plugin.factory = function ($http, options) { 1637 | return new VueAuthenticate($http, options); 1638 | }; 1639 | 1640 | export default plugin; 1641 | -------------------------------------------------------------------------------- /dist/vue-authenticate.min.js: -------------------------------------------------------------------------------- 1 | /** 2 | * vue-authenticate v1.5.0 3 | * https://github.com/dgrubelic/vue-authenticate 4 | * Released under the MIT License. 5 | * 6 | */ 7 | 8 | !function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t="undefined"!=typeof globalThis?globalThis:t||self).VueAuthenticate=e()}(this,function(){"use strict";function o(t){return void 0===t}function s(t){return"function"==typeof t}function p(e,o){return null==e||null==o||Object.keys(o).forEach(function(t){"[object Object]"!=Object.prototype.toString.call(o[t])||"[object Object]"!=Object.prototype.toString.call(e[t])?e[t]=o[t]:e[t]=p(e[t],o[t])}),e}function n(t,e){if(/^(?:[a-z]+:)?\/\//i.test(e))return e;return[t,e].join("/").replace(/[\/]+/g,"/").replace(/\/\?/g,"?").replace(/\/\#/g,"#").replace(/\:\//g,"://")}function u(t){var e="https:"===t.protocol;return t.protocol+"//"+t.hostname+":"+(t.port||(e?"443":"80"))+(/^\//.test(t.pathname)?t.pathname:"/"+t.pathname)}function c(t){var e,o,r={};return(t||"").split("&").forEach(function(t){t&&(o=t.split("="),e=decodeURIComponent(o[0]),r[e]=!o[1]||decodeURIComponent(o[1]))}),r}function r(t){var e;if("undefined"!=typeof module&&module.exports)try{e=require("buffer").Buffer}catch(t){}function o(t){switch(t.length){case 4:var e=((7&t.charCodeAt(0))<<18|(63&t.charCodeAt(1))<<12|(63&t.charCodeAt(2))<<6|63&t.charCodeAt(3))-65536;return r(55296+(e>>>10))+r(56320+(1023&e));case 3:return r((15&t.charCodeAt(0))<<12|(63&t.charCodeAt(1))<<6|63&t.charCodeAt(2));default:return r((31&t.charCodeAt(0))<<6|63&t.charCodeAt(1))}}var r=String.fromCharCode,n=new RegExp(["[À-ß][€-¿]","[à-ï][€-¿]{2}","[ð-÷][€-¿]{3}"].join("|"),"g");return(e?function(t){return(t.constructor===e.constructor?t:new e(t,"base64")).toString()}:function(t){return atob(t).replace(n,o)})(String(t).replace(/[-_]/g,function(t){return"-"===t?"+":"/"}).replace(/[^A-Za-z0-9\+\/]/g,""))}function i(t,e,o){return[encodeURIComponent(t),"=",encodeURIComponent(e),(t=(r=o).path,e=r.domain,o=r.expires,r=r.secure,[null==t?"":";path="+t,null==e?"":";domain="+e,null==o?"":";expires="+o.toUTCString(),null==r||!1===r?"":";secure"].join(""))].join("");var r}"function"!=typeof Object.assign&&(Object.assign=function(t,e){var o=arguments;if(null==t)throw new TypeError("Cannot convert undefined or null to object");for(var r=Object(t),n=1;n 67 | * @copyright Method taken from https://github.com/sahat/satellizer 68 | * @return {Boolean} 69 | */ 70 | isAuthenticated() { 71 | let token = this.storage.getItem(this.tokenName); 72 | 73 | if (token) { 74 | // Token is present 75 | if (token.split('.').length === 3) { 76 | // Token with a valid JWT format XXX.YYY.ZZZ 77 | try { 78 | // Could be a valid JWT or an access token with the same format 79 | const base64Url = token.split('.')[1]; 80 | const base64 = base64Url.replace('-', '+').replace('_', '/'); 81 | const exp = JSON.parse($window.atob(base64)).exp; 82 | if (typeof exp === 'number') { 83 | // JWT with an optonal expiration claims 84 | return Math.round(new Date().getTime() / 1000) < exp; 85 | } 86 | } catch (e) { 87 | return true; // Pass: Non-JWT token that looks like JWT 88 | } 89 | } 90 | return true; // Pass: All other tokens 91 | } 92 | return false; 93 | } 94 | 95 | /** 96 | * Get token if user is authenticated 97 | * @return {String} Authentication token 98 | */ 99 | getToken() { 100 | return this.storage.getItem(this.tokenName); 101 | } 102 | 103 | /** 104 | * Set new authentication token 105 | * @param {String|Object} token 106 | */ 107 | setToken(response, tokenPath) { 108 | if (response[this.options.responseDataKey]) { 109 | response = response[this.options.responseDataKey]; 110 | } 111 | 112 | const responseTokenPath = tokenPath || this.options.tokenPath; 113 | const token = getObjectProperty(response, responseTokenPath); 114 | 115 | if (token) { 116 | this.storage.setItem(this.tokenName, token); 117 | } 118 | } 119 | 120 | getPayload() { 121 | const token = this.storage.getItem(this.tokenName); 122 | 123 | if (token && token.split('.').length === 3) { 124 | try { 125 | const base64Url = token.split('.')[1]; 126 | const base64 = base64Url.replace('-', '+').replace('_', '/'); 127 | return JSON.parse(decodeBase64(base64)); 128 | } catch (e) {} 129 | } 130 | } 131 | 132 | /** 133 | * Login user using email and password 134 | * @param {Object} user User data 135 | * @param {Object} requestOptions Request options 136 | * @return {Promise} Request promise 137 | */ 138 | login(user, requestOptions) { 139 | requestOptions = requestOptions || {}; 140 | requestOptions.url = requestOptions.url 141 | ? requestOptions.url 142 | : joinUrl(this.options.baseUrl, this.options.loginUrl); 143 | requestOptions[this.options.requestDataKey] = 144 | user || requestOptions[this.options.requestDataKey]; 145 | requestOptions.method = requestOptions.method || 'POST'; 146 | requestOptions.withCredentials = 147 | requestOptions.withCredentials || this.options.withCredentials; 148 | 149 | return this.$http(requestOptions).then(response => { 150 | this.setToken(response); 151 | return response; 152 | }); 153 | } 154 | 155 | /** 156 | * Register new user 157 | * @param {Object} user User data 158 | * @param {Object} requestOptions Request options 159 | * @return {Promise} Request promise 160 | */ 161 | register(user, requestOptions) { 162 | requestOptions = requestOptions || {}; 163 | requestOptions.url = requestOptions.url 164 | ? requestOptions.url 165 | : joinUrl(this.options.baseUrl, this.options.registerUrl); 166 | requestOptions[this.options.requestDataKey] = 167 | user || requestOptions[this.options.requestDataKey]; 168 | requestOptions.method = requestOptions.method || 'POST'; 169 | requestOptions.withCredentials = 170 | requestOptions.withCredentials || this.options.withCredentials; 171 | 172 | return this.$http(requestOptions).then(response => { 173 | this.setToken(response); 174 | return response; 175 | }); 176 | } 177 | 178 | /** 179 | * Logout current user 180 | * @param {Object} requestOptions Logout request options object 181 | * @return {Promise} Request promise 182 | */ 183 | logout(requestOptions) { 184 | if (!this.isAuthenticated()) { 185 | return Promise.reject( 186 | new Error('There is no currently authenticated user') 187 | ); 188 | } 189 | 190 | requestOptions = requestOptions || {}; 191 | 192 | if (requestOptions.url || this.options.logoutUrl) { 193 | requestOptions.url = requestOptions.url 194 | ? requestOptions.url 195 | : joinUrl(this.options.baseUrl, this.options.logoutUrl); 196 | requestOptions.method = requestOptions.method || 'POST'; 197 | requestOptions[this.options.requestDataKey] = 198 | requestOptions[this.options.requestDataKey] || undefined; 199 | requestOptions.withCredentials = 200 | requestOptions.withCredentials || this.options.withCredentials; 201 | 202 | return this.$http(requestOptions).then(response => { 203 | this.storage.removeItem(this.tokenName); 204 | return response; 205 | }); 206 | } else { 207 | this.storage.removeItem(this.tokenName); 208 | return Promise.resolve(); 209 | } 210 | } 211 | 212 | /** 213 | * Authenticate user using authentication provider 214 | * 215 | * @param {String} provider Provider name 216 | * @param {Object} userData User data 217 | * @return {Promise} Request promise 218 | */ 219 | authenticate(provider, userData) { 220 | return new Promise((resolve, reject) => { 221 | var providerConfig = this.options.providers[provider]; 222 | if (!providerConfig) { 223 | return reject(new Error('Unknown provider')); 224 | } 225 | 226 | let providerInstance; 227 | switch (providerConfig.oauthType) { 228 | case '1.0': 229 | providerInstance = new OAuth1( 230 | this.$http, 231 | this.storage, 232 | providerConfig, 233 | this.options 234 | ); 235 | break; 236 | case '2.0': 237 | providerInstance = new OAuth2( 238 | this.$http, 239 | this.storage, 240 | providerConfig, 241 | this.options 242 | ); 243 | break; 244 | default: 245 | return reject(new Error('Invalid OAuth type')); 246 | } 247 | 248 | return providerInstance 249 | .init(userData) 250 | .then(response => { 251 | this.setToken(response, providerConfig.tokenPath); 252 | 253 | if (this.isAuthenticated()) { 254 | return resolve(response); 255 | } else { 256 | return reject(new Error('Authentication failed')); 257 | } 258 | }) 259 | .catch(err => reject(err)); 260 | }); 261 | } 262 | 263 | /** 264 | * Link user using authentication provider without login 265 | * 266 | * @param {String} provider Provider name 267 | * @param {Object} userData User data 268 | * @return {Promise} Request promise 269 | */ 270 | link(provider, userData) { 271 | return new Promise((resolve, reject) => { 272 | var providerConfig = this.options.providers[provider]; 273 | if (!providerConfig) { 274 | return reject(new Error('Unknown provider')); 275 | } 276 | 277 | let providerInstance; 278 | switch (providerConfig.oauthType) { 279 | case '1.0': 280 | providerInstance = new OAuth1( 281 | this.$http, 282 | this.storage, 283 | providerConfig, 284 | this.options 285 | ); 286 | break; 287 | case '2.0': 288 | providerInstance = new OAuth2( 289 | this.$http, 290 | this.storage, 291 | providerConfig, 292 | this.options 293 | ); 294 | break; 295 | default: 296 | return reject(new Error('Invalid OAuth type')); 297 | } 298 | 299 | return providerInstance 300 | .init(userData) 301 | .then(response => { 302 | if (response[this.options.responseDataKey]) { 303 | response = response[this.options.responseDataKey]; 304 | } 305 | 306 | resolve(response); 307 | }) 308 | .catch(reject); 309 | }); 310 | } 311 | } 312 | -------------------------------------------------------------------------------- /src/globals.js: -------------------------------------------------------------------------------- 1 | const fakeDocument = { 2 | createElement() { }, 3 | }; 4 | 5 | const fakeWindow = { 6 | atob() { }, 7 | open() { }, 8 | location: {}, 9 | localStorage: { 10 | setItem() { }, 11 | getItem() { }, 12 | removeItem() { }, 13 | }, 14 | sessionStorage: { 15 | setItem() { }, 16 | getItem() { }, 17 | removeItem() { }, 18 | }, 19 | }; 20 | 21 | export const $document = (typeof document !== undefined) 22 | ? document 23 | : fakeDocument; 24 | 25 | export const $window = (typeof window !== undefined) 26 | ? window 27 | : fakeWindow; 28 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import './utils.js'; 2 | import VueAuthenticate from './authenticate.js'; 3 | 4 | /** 5 | * VueAuthenticate plugin 6 | * @param {Object} Vue 7 | * @param {Object} options 8 | */ 9 | function plugin(Vue, options) { 10 | if (plugin.installed) { 11 | return; 12 | } 13 | 14 | plugin.installed = true; 15 | 16 | let vueAuthInstance = null; 17 | Object.defineProperties(Vue.prototype, { 18 | $auth: { 19 | get() { 20 | if (!vueAuthInstance) { 21 | // Request handler library not found, throw error 22 | if (!this.$http) { 23 | throw new Error('Request handler instance not found'); 24 | } 25 | 26 | vueAuthInstance = new VueAuthenticate(this.$http, options); 27 | } 28 | return vueAuthInstance; 29 | }, 30 | }, 31 | }); 32 | } 33 | 34 | /** 35 | * External factory helper for ES5 and CommonJS 36 | * @param {Object} $http Instance of request handling library 37 | * @param {Object} options Configuration object 38 | * @return {VueAuthenticate} VueAuthenticate instance 39 | */ 40 | plugin.factory = function ($http, options) { 41 | return new VueAuthenticate($http, options); 42 | }; 43 | 44 | export default plugin; 45 | -------------------------------------------------------------------------------- /src/oauth/oauth1.js: -------------------------------------------------------------------------------- 1 | import OAuthPopup from './popup.js'; 2 | import { $window } from '../globals.js'; 3 | import { 4 | objectExtend, 5 | isString, 6 | isObject, 7 | isFunction, 8 | joinUrl, 9 | } from '../utils.js'; 10 | 11 | const defaultProviderConfig = { 12 | name: null, 13 | url: null, 14 | authorizationEndpoint: null, 15 | scope: null, 16 | scopePrefix: null, 17 | scopeDelimiter: null, 18 | redirectUri: null, 19 | requiredUrlParams: null, 20 | defaultUrlParams: null, 21 | oauthType: '1.0', 22 | popupOptions: {}, 23 | }; 24 | 25 | export default class OAuth { 26 | constructor($http, storage, providerConfig, options) { 27 | this.$http = $http; 28 | this.storage = storage; 29 | this.providerConfig = objectExtend({}, defaultProviderConfig); 30 | this.providerConfig = objectExtend(this.providerConfig, providerConfig); 31 | this.options = options; 32 | } 33 | 34 | /** 35 | * Initialize OAuth1 process 36 | * @param {Object} userData User data 37 | * @return {Promise} 38 | */ 39 | init(userData) { 40 | this.oauthPopup = new OAuthPopup( 41 | 'about:blank', 42 | this.providerConfig.name, 43 | this.providerConfig.popupOptions 44 | ); 45 | 46 | if (!$window['cordova']) { 47 | this.oauthPopup.open(this.providerConfig.redirectUri, true); 48 | } 49 | 50 | return this.getRequestToken().then(response => { 51 | return this.openPopup(response).then(popupResponse => { 52 | return this.exchangeForToken(popupResponse, userData); 53 | }); 54 | }); 55 | } 56 | 57 | /** 58 | * Get OAuth1 request token 59 | * @return {Promise} 60 | */ 61 | getRequestToken() { 62 | let requestOptions = {}; 63 | requestOptions.method = 'POST'; 64 | requestOptions[this.options.requestDataKey] = objectExtend( 65 | {}, 66 | this.providerConfig 67 | ); 68 | requestOptions.withCredentials = this.options.withCredentials; 69 | if (this.options.baseUrl) { 70 | requestOptions.url = joinUrl( 71 | this.options.baseUrl, 72 | this.providerConfig.url 73 | ); 74 | } else { 75 | requestOptions.url = this.providerConfig.url; 76 | } 77 | 78 | return this.$http(requestOptions); 79 | } 80 | 81 | /** 82 | * Open OAuth1 popup 83 | * @param {Object} response Response object containing request token 84 | * @return {Promise} 85 | */ 86 | openPopup(response) { 87 | const url = [ 88 | this.providerConfig.authorizationEndpoint, 89 | this.buildQueryString(response[this.options.responseDataKey]), 90 | ].join('?'); 91 | 92 | this.oauthPopup.popup.location = url; 93 | if ($window['cordova']) { 94 | return this.oauthPopup.open(this.providerConfig.redirectUri); 95 | } else { 96 | return this.oauthPopup.pooling(this.providerConfig.redirectUri); 97 | } 98 | } 99 | 100 | /** 101 | * Exchange token and token verifier for access token 102 | * @param {Object} oauth OAuth data containing token and token verifier 103 | * @param {Object} userData User data 104 | * @return {Promise} 105 | */ 106 | exchangeForToken(oauth, userData) { 107 | let payload = objectExtend({}, userData); 108 | payload = objectExtend(payload, oauth); 109 | let requestOptions = {}; 110 | requestOptions.method = 'POST'; 111 | requestOptions[this.options.requestDataKey] = payload; 112 | requestOptions.withCredentials = this.options.withCredentials; 113 | if (this.options.baseUrl) { 114 | requestOptions.url = joinUrl( 115 | this.options.baseUrl, 116 | this.providerConfig.url 117 | ); 118 | } else { 119 | requestOptions.url = this.providerConfig.url; 120 | } 121 | return this.$http(requestOptions); 122 | } 123 | 124 | buildQueryString(params) { 125 | const parsedParams = []; 126 | for (var key in params) { 127 | let value = params[key]; 128 | parsedParams.push( 129 | encodeURIComponent(key) + '=' + encodeURIComponent(value) 130 | ); 131 | } 132 | return parsedParams.join('&'); 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /src/oauth/oauth2.js: -------------------------------------------------------------------------------- 1 | import OAuthPopup from './popup.js'; 2 | import { 3 | camelCase, 4 | isFunction, 5 | isString, 6 | objectExtend, 7 | joinUrl, 8 | } from '../utils.js'; 9 | 10 | /** 11 | * Default provider configuration 12 | * @type {Object} 13 | */ 14 | const defaultProviderConfig = { 15 | name: null, 16 | url: null, 17 | clientId: null, 18 | authorizationEndpoint: null, 19 | redirectUri: null, 20 | scope: null, 21 | scopePrefix: null, 22 | scopeDelimiter: null, 23 | state: null, 24 | requiredUrlParams: null, 25 | defaultUrlParams: ['response_type', 'client_id', 'redirect_uri'], 26 | responseType: 'code', 27 | responseParams: { 28 | code: 'code', 29 | clientId: 'clientId', 30 | redirectUri: 'redirectUri', 31 | }, 32 | oauthType: '2.0', 33 | popupOptions: {}, 34 | }; 35 | 36 | export default class OAuth2 { 37 | constructor($http, storage, providerConfig, options) { 38 | this.$http = $http; 39 | this.storage = storage; 40 | this.providerConfig = objectExtend({}, defaultProviderConfig); 41 | this.providerConfig = objectExtend(this.providerConfig, providerConfig); 42 | this.options = options; 43 | } 44 | 45 | init(userData) { 46 | let stateName = this.providerConfig.name + '_state'; 47 | if (isFunction(this.providerConfig.state)) { 48 | this.storage.setItem(stateName, this.providerConfig.state()); 49 | } else if (isString(this.providerConfig.state)) { 50 | this.storage.setItem(stateName, this.providerConfig.state); 51 | } 52 | 53 | let url = [ 54 | this.providerConfig.authorizationEndpoint, 55 | this._stringifyRequestParams(), 56 | ].join('?'); 57 | 58 | this.oauthPopup = new OAuthPopup( 59 | url, 60 | this.providerConfig.name, 61 | this.providerConfig.popupOptions 62 | ); 63 | 64 | return new Promise((resolve, reject) => { 65 | this.oauthPopup 66 | .open(this.providerConfig.redirectUri) 67 | .then(response => { 68 | if ( 69 | this.providerConfig.responseType === 'token' || 70 | !this.providerConfig.url 71 | ) { 72 | return resolve(response); 73 | } 74 | 75 | if ( 76 | response.state && 77 | response.state !== this.storage.getItem(stateName) 78 | ) { 79 | return reject( 80 | new Error( 81 | 'State parameter value does not match original OAuth request state value' 82 | ) 83 | ); 84 | } 85 | 86 | resolve(this.exchangeForToken(response, userData)); 87 | }) 88 | .catch(err => { 89 | reject(err); 90 | }); 91 | }); 92 | } 93 | 94 | /** 95 | * Exchange temporary oauth data for access token 96 | * @author Sahat Yalkabov 97 | * @copyright Method taken from https://github.com/sahat/satellizer 98 | * 99 | * @param {[type]} oauth [description] 100 | * @param {[type]} userData [description] 101 | * @return {[type]} [description] 102 | */ 103 | exchangeForToken(oauth, userData) { 104 | let payload = objectExtend({}, userData); 105 | 106 | for (let key in this.providerConfig.responseParams) { 107 | let value = this.providerConfig.responseParams[key]; 108 | 109 | switch (key) { 110 | case 'code': 111 | payload[key] = oauth.code; 112 | break; 113 | case 'clientId': 114 | payload[key] = this.providerConfig.clientId; 115 | break; 116 | case 'redirectUri': 117 | payload[key] = this.providerConfig.redirectUri; 118 | break; 119 | default: 120 | payload[key] = oauth[key]; 121 | } 122 | } 123 | 124 | if (oauth.state) { 125 | payload.state = oauth.state; 126 | } 127 | 128 | let exchangeTokenUrl; 129 | if (this.options.baseUrl) { 130 | exchangeTokenUrl = joinUrl(this.options.baseUrl, this.providerConfig.url); 131 | } else { 132 | exchangeTokenUrl = this.providerConfig.url; 133 | } 134 | 135 | return this.$http.post(exchangeTokenUrl, payload, { 136 | withCredentials: this.options.withCredentials, 137 | }); 138 | } 139 | 140 | /** 141 | * Stringify oauth params 142 | * @author Sahat Yalkabov 143 | * @copyright Method taken from https://github.com/sahat/satellizer 144 | * 145 | * @return {String} 146 | */ 147 | _stringifyRequestParams() { 148 | let keyValuePairs = []; 149 | let paramCategories = [ 150 | 'defaultUrlParams', 151 | 'requiredUrlParams', 152 | 'optionalUrlParams', 153 | ]; 154 | 155 | paramCategories.forEach(categoryName => { 156 | if (!this.providerConfig[categoryName]) return; 157 | if (!Array.isArray(this.providerConfig[categoryName])) return; 158 | 159 | this.providerConfig[categoryName].forEach(paramName => { 160 | let camelCaseParamName = camelCase(paramName); 161 | let paramValue = isFunction(this.providerConfig[paramName]) 162 | ? this.providerConfig[paramName]() 163 | : this.providerConfig[camelCaseParamName]; 164 | 165 | if (paramName === 'redirect_uri' && !paramValue) return; 166 | 167 | if (paramName === 'state') { 168 | let stateName = this.providerConfig.name + '_state'; 169 | paramValue = encodeURIComponent(this.storage.getItem(stateName)); 170 | } 171 | if (paramName === 'scope' && Array.isArray(paramValue)) { 172 | paramValue = paramValue.join(this.providerConfig.scopeDelimiter); 173 | if (this.providerConfig.scopePrefix) { 174 | paramValue = [this.providerConfig.scopePrefix, paramValue].join( 175 | this.providerConfig.scopeDelimiter 176 | ); 177 | } 178 | } 179 | 180 | keyValuePairs.push([paramName, paramValue]); 181 | }); 182 | }); 183 | 184 | return keyValuePairs 185 | .map(param => { 186 | return param.join('='); 187 | }) 188 | .join('&'); 189 | } 190 | } 191 | -------------------------------------------------------------------------------- /src/oauth/popup.js: -------------------------------------------------------------------------------- 1 | import Promise from '../promise.js'; 2 | import { $document, $window } from '../globals.js'; 3 | import { 4 | objectExtend, 5 | parseQueryString, 6 | getFullUrlPath, 7 | isUndefined, 8 | } from '../utils.js'; 9 | 10 | /** 11 | * OAuth2 popup management class 12 | * 13 | * @author Sahat Yalkabov 14 | * @copyright Class mostly taken from https://github.com/sahat/satellizer 15 | * and adjusted to fit vue-authenticate library 16 | */ 17 | export default class OAuthPopup { 18 | constructor(url, name, popupOptions) { 19 | this.popup = null; 20 | this.url = url; 21 | this.name = name; 22 | this.popupOptions = popupOptions; 23 | } 24 | 25 | open(redirectUri, skipPooling) { 26 | try { 27 | this.popup = $window.open(this.url, this.name, this._stringifyOptions()); 28 | if (this.popup && this.popup.focus) { 29 | this.popup.focus(); 30 | } 31 | 32 | if (skipPooling) { 33 | return Promise.resolve(); 34 | } else { 35 | return this.pooling(redirectUri); 36 | } 37 | } catch (e) { 38 | return Promise.reject(new Error('OAuth popup error occurred')); 39 | } 40 | } 41 | 42 | pooling(redirectUri) { 43 | return new Promise((resolve, reject) => { 44 | const redirectUriParser = $document.createElement('a'); 45 | redirectUriParser.href = redirectUri; 46 | const redirectUriPath = getFullUrlPath(redirectUriParser); 47 | 48 | let poolingInterval = setInterval(() => { 49 | if ( 50 | !this.popup || 51 | this.popup.closed || 52 | this.popup.closed === undefined 53 | ) { 54 | clearInterval(poolingInterval); 55 | poolingInterval = null; 56 | reject(new Error('Auth popup window closed')); 57 | } 58 | 59 | try { 60 | const popupWindowPath = getFullUrlPath(this.popup.location); 61 | 62 | if (popupWindowPath === redirectUriPath) { 63 | if (this.popup.location.search || this.popup.location.hash) { 64 | const query = parseQueryString( 65 | this.popup.location.search.substring(1).replace(/\/$/, '') 66 | ); 67 | const hash = parseQueryString( 68 | this.popup.location.hash.substring(1).replace(/[\/$]/, '') 69 | ); 70 | let params = objectExtend({}, query); 71 | params = objectExtend(params, hash); 72 | 73 | if (params.error) { 74 | reject(new Error(params.error)); 75 | } else { 76 | resolve(params); 77 | } 78 | } else { 79 | reject( 80 | new Error( 81 | 'OAuth redirect has occurred but no query or hash parameters were found.' 82 | ) 83 | ); 84 | } 85 | 86 | clearInterval(poolingInterval); 87 | poolingInterval = null; 88 | this.popup.close(); 89 | } 90 | } catch (e) { 91 | // Ignore DOMException: Blocked a frame with origin from accessing a cross-origin frame. 92 | } 93 | }, 250); 94 | }); 95 | } 96 | 97 | _stringifyOptions() { 98 | let options = []; 99 | for (var optionKey in this.popupOptions) { 100 | if (!isUndefined(this.popupOptions[optionKey])) { 101 | options.push(`${optionKey}=${this.popupOptions[optionKey]}`); 102 | } 103 | } 104 | return options.join(','); 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /src/options.js: -------------------------------------------------------------------------------- 1 | import { isUndefined } from './utils'; 2 | import { $window } from './globals'; 3 | 4 | export function getCookieDomainUrl() { 5 | try { 6 | return $window.location.hostname; 7 | } catch (e) {} 8 | 9 | return ''; 10 | } 11 | 12 | export function getRedirectUri(uri) { 13 | try { 14 | return !isUndefined(uri) 15 | ? `${$window.location.origin}${uri}` 16 | : $window.location.origin; 17 | } catch (e) {} 18 | 19 | return uri || null; 20 | } 21 | 22 | /** 23 | * Default configuration 24 | */ 25 | export default { 26 | baseUrl: null, 27 | tokenPath: 'access_token', 28 | tokenName: 'token', 29 | tokenPrefix: 'vueauth', 30 | tokenHeader: 'Authorization', 31 | tokenType: 'Bearer', 32 | loginUrl: '/auth/login', 33 | registerUrl: '/auth/register', 34 | logoutUrl: null, 35 | storageType: 'localStorage', 36 | storageNamespace: 'vue-authenticate', 37 | cookieStorage: { 38 | domain: getCookieDomainUrl(), 39 | path: '/', 40 | secure: false, 41 | }, 42 | requestDataKey: 'data', 43 | responseDataKey: 'data', 44 | 45 | /** 46 | * Default request interceptor for Axios library 47 | * @context {VueAuthenticate} 48 | */ 49 | bindRequestInterceptor: function ($auth) { 50 | const tokenHeader = $auth.options.tokenHeader; 51 | 52 | $auth.$http.interceptors.request.use(config => { 53 | if ($auth.isAuthenticated()) { 54 | config.headers[tokenHeader] = [ 55 | $auth.options.tokenType, 56 | $auth.getToken(), 57 | ].join(' '); 58 | } else { 59 | delete config.headers[tokenHeader]; 60 | } 61 | return config; 62 | }); 63 | }, 64 | 65 | providers: { 66 | facebook: { 67 | name: 'facebook', 68 | url: '/auth/facebook', 69 | authorizationEndpoint: 'https://www.facebook.com/v10.0/dialog/oauth', 70 | redirectUri: getRedirectUri('/'), 71 | requiredUrlParams: ['display', 'scope'], 72 | scope: ['email'], 73 | scopeDelimiter: ',', 74 | display: 'popup', 75 | oauthType: '2.0', 76 | popupOptions: { width: 580, height: 400 }, 77 | }, 78 | 79 | google: { 80 | name: 'google', 81 | url: '/auth/google', 82 | authorizationEndpoint: 'https://accounts.google.com/o/oauth2/auth', 83 | redirectUri: getRedirectUri(), 84 | requiredUrlParams: ['scope'], 85 | optionalUrlParams: ['display'], 86 | scope: ['profile', 'email'], 87 | scopePrefix: 'openid', 88 | scopeDelimiter: ' ', 89 | display: 'popup', 90 | oauthType: '2.0', 91 | popupOptions: { width: 452, height: 633 }, 92 | }, 93 | 94 | github: { 95 | name: 'github', 96 | url: '/auth/github', 97 | authorizationEndpoint: 'https://github.com/login/oauth/authorize', 98 | redirectUri: getRedirectUri(), 99 | optionalUrlParams: ['scope'], 100 | scope: ['user:email'], 101 | scopeDelimiter: ' ', 102 | oauthType: '2.0', 103 | popupOptions: { width: 1020, height: 618 }, 104 | }, 105 | 106 | instagram: { 107 | name: 'instagram', 108 | url: '/auth/instagram', 109 | authorizationEndpoint: 'https://api.instagram.com/oauth/authorize', 110 | redirectUri: getRedirectUri(), 111 | requiredUrlParams: ['scope'], 112 | scope: ['basic'], 113 | scopeDelimiter: '+', 114 | oauthType: '2.0', 115 | popupOptions: { width: null, height: null }, 116 | }, 117 | 118 | twitter: { 119 | name: 'twitter', 120 | url: '/auth/twitter', 121 | authorizationEndpoint: 'https://api.twitter.com/oauth/authenticate', 122 | redirectUri: getRedirectUri(), 123 | oauthType: '1.0', 124 | popupOptions: { width: 495, height: 645 }, 125 | }, 126 | 127 | bitbucket: { 128 | name: 'bitbucket', 129 | url: '/auth/bitbucket', 130 | authorizationEndpoint: 'https://bitbucket.org/site/oauth2/authorize', 131 | redirectUri: getRedirectUri('/'), 132 | optionalUrlParams: ['scope'], 133 | scope: ['email'], 134 | scopeDelimiter: ' ', 135 | oauthType: '2.0', 136 | popupOptions: { width: 1020, height: 618 }, 137 | }, 138 | 139 | linkedin: { 140 | name: 'linkedin', 141 | url: '/auth/linkedin', 142 | authorizationEndpoint: 'https://www.linkedin.com/oauth/v2/authorization', 143 | redirectUri: getRedirectUri(), 144 | requiredUrlParams: ['state'], 145 | scope: ['r_emailaddress'], 146 | scopeDelimiter: ' ', 147 | state: 'STATE', 148 | oauthType: '2.0', 149 | popupOptions: { width: 527, height: 582 }, 150 | }, 151 | 152 | live: { 153 | name: 'live', 154 | url: '/auth/live', 155 | authorizationEndpoint: 'https://login.live.com/oauth20_authorize.srf', 156 | redirectUri: getRedirectUri(), 157 | requiredUrlParams: ['display', 'scope'], 158 | scope: ['wl.emails'], 159 | scopeDelimiter: ' ', 160 | display: 'popup', 161 | oauthType: '2.0', 162 | popupOptions: { width: 500, height: 560 }, 163 | }, 164 | 165 | oauth1: { 166 | name: null, 167 | url: '/auth/oauth1', 168 | authorizationEndpoint: null, 169 | redirectUri: getRedirectUri(), 170 | oauthType: '1.0', 171 | popupOptions: null, 172 | }, 173 | 174 | oauth2: { 175 | name: null, 176 | url: '/auth/oauth2', 177 | clientId: null, 178 | redirectUri: getRedirectUri(), 179 | authorizationEndpoint: null, 180 | defaultUrlParams: ['response_type', 'client_id', 'redirect_uri'], 181 | requiredUrlParams: null, 182 | optionalUrlParams: null, 183 | scope: null, 184 | scopePrefix: null, 185 | scopeDelimiter: null, 186 | state: null, 187 | oauthType: '2.0', 188 | popupOptions: null, 189 | responseType: 'code', 190 | responseParams: { 191 | code: 'code', 192 | clientId: 'clientId', 193 | redirectUri: 'redirectUri', 194 | }, 195 | }, 196 | }, 197 | }; 198 | -------------------------------------------------------------------------------- /src/promise.js: -------------------------------------------------------------------------------- 1 | // Store setTimeout reference so promise-polyfill will be unaffected by 2 | // other code modifying setTimeout (like sinon.useFakeTimers()) 3 | var setTimeoutFunc = setTimeout; 4 | 5 | function noop() {} 6 | 7 | // Polyfill for Function.prototype.bind 8 | function bind(fn, thisArg) { 9 | return function () { 10 | fn.apply(thisArg, arguments); 11 | }; 12 | } 13 | 14 | function Promise(fn) { 15 | if (typeof this !== 'object') 16 | throw new TypeError('Promises must be constructed via new'); 17 | if (typeof fn !== 'function') throw new TypeError('not a function'); 18 | this._state = 0; 19 | this._handled = false; 20 | this._value = undefined; 21 | this._deferreds = []; 22 | 23 | doResolve(fn, this); 24 | } 25 | 26 | function handle(self, deferred) { 27 | while (self._state === 3) { 28 | self = self._value; 29 | } 30 | if (self._state === 0) { 31 | self._deferreds.push(deferred); 32 | return; 33 | } 34 | self._handled = true; 35 | Promise._immediateFn(function () { 36 | var cb = self._state === 1 ? deferred.onFulfilled : deferred.onRejected; 37 | if (cb === null) { 38 | (self._state === 1 ? resolve : reject)(deferred.promise, self._value); 39 | return; 40 | } 41 | var ret; 42 | try { 43 | ret = cb(self._value); 44 | } catch (e) { 45 | reject(deferred.promise, e); 46 | return; 47 | } 48 | resolve(deferred.promise, ret); 49 | }); 50 | } 51 | 52 | function resolve(self, newValue) { 53 | try { 54 | // Promise Resolution Procedure: https://github.com/promises-aplus/promises-spec#the-promise-resolution-procedure 55 | if (newValue === self) 56 | throw new TypeError('A promise cannot be resolved with itself.'); 57 | if ( 58 | newValue && 59 | (typeof newValue === 'object' || typeof newValue === 'function') 60 | ) { 61 | var then = newValue.then; 62 | if (newValue instanceof Promise) { 63 | self._state = 3; 64 | self._value = newValue; 65 | finale(self); 66 | return; 67 | } else if (typeof then === 'function') { 68 | doResolve(bind(then, newValue), self); 69 | return; 70 | } 71 | } 72 | self._state = 1; 73 | self._value = newValue; 74 | finale(self); 75 | } catch (e) { 76 | reject(self, e); 77 | } 78 | } 79 | 80 | function reject(self, newValue) { 81 | self._state = 2; 82 | self._value = newValue; 83 | finale(self); 84 | } 85 | 86 | function finale(self) { 87 | if (self._state === 2 && self._deferreds.length === 0) { 88 | Promise._immediateFn(function () { 89 | if (!self._handled) { 90 | Promise._unhandledRejectionFn(self._value); 91 | } 92 | }); 93 | } 94 | 95 | for (var i = 0, len = self._deferreds.length; i < len; i++) { 96 | handle(self, self._deferreds[i]); 97 | } 98 | self._deferreds = null; 99 | } 100 | 101 | function Handler(onFulfilled, onRejected, promise) { 102 | this.onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : null; 103 | this.onRejected = typeof onRejected === 'function' ? onRejected : null; 104 | this.promise = promise; 105 | } 106 | 107 | /** 108 | * Take a potentially misbehaving resolver function and make sure 109 | * onFulfilled and onRejected are only called once. 110 | * 111 | * Makes no guarantees about asynchrony. 112 | */ 113 | function doResolve(fn, self) { 114 | var done = false; 115 | try { 116 | fn( 117 | function (value) { 118 | if (done) return; 119 | done = true; 120 | resolve(self, value); 121 | }, 122 | function (reason) { 123 | if (done) return; 124 | done = true; 125 | reject(self, reason); 126 | } 127 | ); 128 | } catch (ex) { 129 | if (done) return; 130 | done = true; 131 | reject(self, ex); 132 | } 133 | } 134 | 135 | Promise.prototype['catch'] = function (onRejected) { 136 | return this.then(null, onRejected); 137 | }; 138 | 139 | Promise.prototype.then = function (onFulfilled, onRejected) { 140 | var prom = new this.constructor(noop); 141 | 142 | handle(this, new Handler(onFulfilled, onRejected, prom)); 143 | return prom; 144 | }; 145 | 146 | Promise.all = function (arr) { 147 | var args = Array.prototype.slice.call(arr); 148 | 149 | return new Promise(function (resolve, reject) { 150 | if (args.length === 0) return resolve([]); 151 | var remaining = args.length; 152 | 153 | function res(i, val) { 154 | try { 155 | if (val && (typeof val === 'object' || typeof val === 'function')) { 156 | var then = val.then; 157 | if (typeof then === 'function') { 158 | then.call( 159 | val, 160 | function (val) { 161 | res(i, val); 162 | }, 163 | reject 164 | ); 165 | return; 166 | } 167 | } 168 | args[i] = val; 169 | if (--remaining === 0) { 170 | resolve(args); 171 | } 172 | } catch (ex) { 173 | reject(ex); 174 | } 175 | } 176 | 177 | for (var i = 0; i < args.length; i++) { 178 | res(i, args[i]); 179 | } 180 | }); 181 | }; 182 | 183 | Promise.resolve = function (value) { 184 | if (value && typeof value === 'object' && value.constructor === Promise) { 185 | return value; 186 | } 187 | 188 | return new Promise(function (resolve) { 189 | resolve(value); 190 | }); 191 | }; 192 | 193 | Promise.reject = function (value) { 194 | return new Promise(function (resolve, reject) { 195 | reject(value); 196 | }); 197 | }; 198 | 199 | Promise.race = function (values) { 200 | return new Promise(function (resolve, reject) { 201 | for (var i = 0, len = values.length; i < len; i++) { 202 | values[i].then(resolve, reject); 203 | } 204 | }); 205 | }; 206 | 207 | // Use polyfill for setImmediate for performance gains 208 | Promise._immediateFn = 209 | (typeof setImmediate === 'function' && 210 | function (fn) { 211 | setImmediate(fn); 212 | }) || 213 | function (fn) { 214 | setTimeoutFunc(fn, 0); 215 | }; 216 | 217 | Promise._unhandledRejectionFn = function _unhandledRejectionFn(err) { 218 | if (typeof console !== 'undefined' && console) { 219 | console.warn('Possible Unhandled Promise Rejection:', err); // eslint-disable-line no-console 220 | } 221 | }; 222 | 223 | /** 224 | * Set the immediate function to execute callbacks 225 | * @param fn {function} Function to execute 226 | * @deprecated 227 | */ 228 | Promise._setImmediateFn = function _setImmediateFn(fn) { 229 | Promise._immediateFn = fn; 230 | }; 231 | 232 | /** 233 | * Change the function to execute on unhandled rejection 234 | * @param {function} fn Function to execute on unhandled rejection 235 | * @deprecated 236 | */ 237 | Promise._setUnhandledRejectionFn = function _setUnhandledRejectionFn(fn) { 238 | Promise._unhandledRejectionFn = fn; 239 | }; 240 | 241 | export default Promise; 242 | -------------------------------------------------------------------------------- /src/storage.js: -------------------------------------------------------------------------------- 1 | import { $window } from './globals'; 2 | import CookieStorage from './storage/cookie-storage.js'; 3 | import LocalStorage from './storage/local-storage.js'; 4 | import MemoryStorage from './storage/memory-storage.js'; 5 | import SessionStorage from './storage/session-storage.js'; 6 | 7 | export default function StorageFactory(options) { 8 | switch (options.storageType) { 9 | case 'localStorage': 10 | try { 11 | $window.localStorage.setItem('testKey', 'test'); 12 | $window.localStorage.removeItem('testKey'); 13 | return new LocalStorage(options.storageNamespace); 14 | } catch (e) {} 15 | 16 | case 'sessionStorage': 17 | try { 18 | $window.sessionStorage.setItem('testKey', 'test'); 19 | $window.sessionStorage.removeItem('testKey'); 20 | return new SessionStorage(options.storageNamespace); 21 | } catch (e) {} 22 | 23 | case 'cookieStorage': 24 | return new CookieStorage(options.cookieStorage); 25 | 26 | case 'memoryStorage': 27 | default: 28 | return new MemoryStorage(options.storageNamespace); 29 | break; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/storage/cookie-storage.js: -------------------------------------------------------------------------------- 1 | import { $document } from '../globals.js'; 2 | import { objectExtend, formatCookie, parseCookies } from '../utils.js'; 3 | import { getCookieDomainUrl } from '../options.js'; 4 | 5 | class CookieStorage { 6 | constructor(defaultOptions) { 7 | this._defaultOptions = objectExtend( 8 | { 9 | domain: getCookieDomainUrl(), 10 | expires: null, 11 | path: '/', 12 | secure: false, 13 | }, 14 | defaultOptions 15 | ); 16 | } 17 | 18 | setItem(key, value) { 19 | const options = objectExtend({}, this._defaultOptions); 20 | const cookie = formatCookie(key, value, options); 21 | this._setCookie(cookie); 22 | } 23 | 24 | getItem(key) { 25 | const cookies = parseCookies(this._getCookie()); 26 | return cookies.hasOwnProperty(key) ? cookies[key] : null; 27 | } 28 | 29 | removeItem(key) { 30 | const value = ''; 31 | const defaultOptions = objectExtend({}, this._defaultOptions); 32 | const options = objectExtend(defaultOptions, { 33 | expires: new Date(0), 34 | }); 35 | const cookie = formatCookie(key, value, options); 36 | this._setCookie(cookie); 37 | } 38 | 39 | _getCookie() { 40 | try { 41 | return $document.cookie === 'undefined' ? '' : $document.cookie; 42 | } catch (e) {} 43 | 44 | return ''; 45 | } 46 | 47 | _setCookie(cookie) { 48 | try { 49 | $document.cookie = cookie; 50 | } catch (e) {} 51 | } 52 | } 53 | 54 | export default CookieStorage; 55 | -------------------------------------------------------------------------------- /src/storage/local-storage.js: -------------------------------------------------------------------------------- 1 | import { $window } from '../globals.js'; 2 | 3 | class LocalStorage { 4 | constructor(namespace) { 5 | this.namespace = namespace || null; 6 | } 7 | 8 | setItem(key, value) { 9 | $window.localStorage.setItem(this._getStorageKey(key), value); 10 | } 11 | 12 | getItem(key) { 13 | return $window.localStorage.getItem(this._getStorageKey(key)); 14 | } 15 | 16 | removeItem(key) { 17 | $window.localStorage.removeItem(this._getStorageKey(key)); 18 | } 19 | 20 | _getStorageKey(key) { 21 | if (this.namespace) { 22 | return [this.namespace, key].join('.'); 23 | } 24 | return key; 25 | } 26 | } 27 | 28 | export default LocalStorage; 29 | -------------------------------------------------------------------------------- /src/storage/memory-storage.js: -------------------------------------------------------------------------------- 1 | class MemoryStorage { 2 | constructor(namespace) { 3 | this.namespace = namespace || null; 4 | this._storage = {}; 5 | } 6 | 7 | setItem(key, value) { 8 | this._storage[this._getStorageKey(key)] = value; 9 | } 10 | 11 | getItem(key) { 12 | return this._storage[this._getStorageKey(key)]; 13 | } 14 | 15 | removeItem(key) { 16 | delete this._storage[this._getStorageKey(key)]; 17 | } 18 | 19 | _getStorageKey(key) { 20 | if (this.namespace) { 21 | return [this.namespace, key].join('.'); 22 | } 23 | return key; 24 | } 25 | } 26 | 27 | export default MemoryStorage; 28 | -------------------------------------------------------------------------------- /src/storage/session-storage.js: -------------------------------------------------------------------------------- 1 | import { $window } from '../globals.js'; 2 | 3 | class SessionStorage { 4 | constructor(namespace) { 5 | this.namespace = namespace || null; 6 | } 7 | 8 | setItem(key, value) { 9 | $window.sessionStorage.setItem(this._getStorageKey(key), value); 10 | } 11 | 12 | getItem(key) { 13 | return $window.sessionStorage.getItem(this._getStorageKey(key)); 14 | } 15 | 16 | removeItem(key) { 17 | $window.sessionStorage.removeItem(this._getStorageKey(key)); 18 | } 19 | 20 | _getStorageKey(key) { 21 | if (this.namespace) { 22 | return [this.namespace, key].join('.'); 23 | } 24 | return key; 25 | } 26 | } 27 | 28 | export default SessionStorage; 29 | -------------------------------------------------------------------------------- /src/utils.js: -------------------------------------------------------------------------------- 1 | if (typeof Object.assign != 'function') { 2 | Object.assign = function (target, varArgs) { 3 | 'use strict'; 4 | if (target == null) { 5 | throw new TypeError('Cannot convert undefined or null to object'); 6 | } 7 | 8 | var to = Object(target); 9 | 10 | for (var index = 1; index < arguments.length; index++) { 11 | var nextSource = arguments[index]; 12 | 13 | if (nextSource != null) { 14 | // Skip over if undefined or null 15 | for (var nextKey in nextSource) { 16 | // Avoid bugs when hasOwnProperty is shadowed 17 | if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) { 18 | to[nextKey] = nextSource[nextKey]; 19 | } 20 | } 21 | } 22 | } 23 | return to; 24 | }; 25 | } 26 | 27 | export function camelCase(name) { 28 | return name.replace(/([\:\-\_]+(.))/g, function ( 29 | _, 30 | separator, 31 | letter, 32 | offset 33 | ) { 34 | return offset ? letter.toUpperCase() : letter; 35 | }); 36 | } 37 | 38 | export function isUndefined(value) { 39 | return typeof value === 'undefined'; 40 | } 41 | 42 | export function isDefined(value) { 43 | return typeof value !== 'undefined'; 44 | } 45 | 46 | export function isObject(value) { 47 | return value !== null && typeof value === 'object'; 48 | } 49 | 50 | export function isString(value) { 51 | return typeof value === 'string'; 52 | } 53 | 54 | export function isNumber(value) { 55 | return typeof value === 'number'; 56 | } 57 | 58 | export function isFunction(value) { 59 | return typeof value === 'function'; 60 | } 61 | 62 | export function objectExtend(a, b) { 63 | // Don't touch 'null' or 'undefined' objects. 64 | if (a == null || b == null) { 65 | return a; 66 | } 67 | 68 | Object.keys(b).forEach(function (key) { 69 | if (Object.prototype.toString.call(b[key]) == '[object Object]') { 70 | if (Object.prototype.toString.call(a[key]) != '[object Object]') { 71 | a[key] = b[key]; 72 | } else { 73 | a[key] = objectExtend(a[key], b[key]); 74 | } 75 | } else { 76 | a[key] = b[key]; 77 | } 78 | }); 79 | 80 | return a; 81 | } 82 | 83 | /** 84 | * Assemble url from two segments 85 | * 86 | * @author Sahat Yalkabov 87 | * @copyright Method taken from https://github.com/sahat/satellizer 88 | * 89 | * @param {String} baseUrl Base url 90 | * @param {String} url URI 91 | * @return {String} 92 | */ 93 | export function joinUrl(baseUrl, url) { 94 | if (/^(?:[a-z]+:)?\/\//i.test(url)) { 95 | return url; 96 | } 97 | let joined = [baseUrl, url].join('/'); 98 | let normalize = function (str) { 99 | return str 100 | .replace(/[\/]+/g, '/') 101 | .replace(/\/\?/g, '?') 102 | .replace(/\/\#/g, '#') 103 | .replace(/\:\//g, '://'); 104 | }; 105 | return normalize(joined); 106 | } 107 | 108 | /** 109 | * Get full path based on current location 110 | * 111 | * @author Sahat Yalkabov 112 | * @copyright Method taken from https://github.com/sahat/satellizer 113 | * 114 | * @param {Location} location 115 | * @return {String} 116 | */ 117 | export function getFullUrlPath(location) { 118 | const isHttps = location.protocol === 'https:'; 119 | return ( 120 | location.protocol + 121 | '//' + 122 | location.hostname + 123 | ':' + 124 | (location.port || (isHttps ? '443' : '80')) + 125 | (/^\//.test(location.pathname) 126 | ? location.pathname 127 | : '/' + location.pathname) 128 | ); 129 | } 130 | 131 | /** 132 | * Parse query string variables 133 | * 134 | * @author Sahat Yalkabov 135 | * @copyright Method taken from https://github.com/sahat/satellizer 136 | * 137 | * @param {String} Query string 138 | * @return {String} 139 | */ 140 | export function parseQueryString(str) { 141 | let obj = {}; 142 | let key; 143 | let value; 144 | (str || '').split('&').forEach(keyValue => { 145 | if (keyValue) { 146 | value = keyValue.split('='); 147 | key = decodeURIComponent(value[0]); 148 | obj[key] = !!value[1] ? decodeURIComponent(value[1]) : true; 149 | } 150 | }); 151 | return obj; 152 | } 153 | 154 | /** 155 | * Decode base64 string 156 | * @author Sahat Yalkabov 157 | * @copyright Method taken from https://github.com/sahat/satellizer 158 | * 159 | * @param {String} str base64 encoded string 160 | * @return {Object} 161 | */ 162 | export function decodeBase64(str) { 163 | let buffer; 164 | if (typeof module !== 'undefined' && module.exports) { 165 | try { 166 | buffer = require('buffer').Buffer; 167 | } catch (err) { 168 | // noop 169 | } 170 | } 171 | 172 | let fromCharCode = String.fromCharCode; 173 | 174 | let re_btou = new RegExp( 175 | [ 176 | '[\xC0-\xDF][\x80-\xBF]', 177 | '[\xE0-\xEF][\x80-\xBF]{2}', 178 | '[\xF0-\xF7][\x80-\xBF]{3}', 179 | ].join('|'), 180 | 'g' 181 | ); 182 | 183 | let cb_btou = function (cccc) { 184 | switch (cccc.length) { 185 | case 4: 186 | let cp = 187 | ((0x07 & cccc.charCodeAt(0)) << 18) | 188 | ((0x3f & cccc.charCodeAt(1)) << 12) | 189 | ((0x3f & cccc.charCodeAt(2)) << 6) | 190 | (0x3f & cccc.charCodeAt(3)); 191 | let offset = cp - 0x10000; 192 | return ( 193 | fromCharCode((offset >>> 10) + 0xd800) + 194 | fromCharCode((offset & 0x3ff) + 0xdc00) 195 | ); 196 | case 3: 197 | return fromCharCode( 198 | ((0x0f & cccc.charCodeAt(0)) << 12) | 199 | ((0x3f & cccc.charCodeAt(1)) << 6) | 200 | (0x3f & cccc.charCodeAt(2)) 201 | ); 202 | default: 203 | return fromCharCode( 204 | ((0x1f & cccc.charCodeAt(0)) << 6) | (0x3f & cccc.charCodeAt(1)) 205 | ); 206 | } 207 | }; 208 | 209 | let btou = function (b) { 210 | return b.replace(re_btou, cb_btou); 211 | }; 212 | 213 | let _decode = buffer 214 | ? function (a) { 215 | return (a.constructor === buffer.constructor 216 | ? a 217 | : new buffer(a, 'base64') 218 | ).toString(); 219 | } 220 | : function (a) { 221 | return btou(atob(a)); 222 | }; 223 | 224 | return _decode( 225 | String(str) 226 | .replace(/[-_]/g, function (m0) { 227 | return m0 === '-' ? '+' : '/'; 228 | }) 229 | .replace(/[^A-Za-z0-9\+\/]/g, '') 230 | ); 231 | } 232 | 233 | export function parseCookies(str = '') { 234 | if (str.length === 0) return {}; 235 | const parsed = {}; 236 | const pattern = new RegExp('\\s*;\\s*'); 237 | str.split(pattern).forEach(i => { 238 | const [encodedKey, encodedValue] = i.split('='); 239 | const key = decodeURIComponent(encodedKey); 240 | const value = decodeURIComponent(encodedValue); 241 | parsed[key] = value; 242 | }); 243 | return parsed; 244 | } 245 | 246 | export function formatOptions(options) { 247 | const { path, domain, expires, secure } = options; 248 | return [ 249 | typeof path === 'undefined' || path === null ? '' : ';path=' + path, 250 | typeof domain === 'undefined' || domain === null ? '' : ';domain=' + domain, 251 | typeof expires === 'undefined' || expires === null 252 | ? '' 253 | : ';expires=' + expires.toUTCString(), 254 | typeof secure === 'undefined' || secure === null || secure === false 255 | ? '' 256 | : ';secure', 257 | ].join(''); 258 | } 259 | 260 | export function formatCookie(key, value, options) { 261 | return [ 262 | encodeURIComponent(key), 263 | '=', 264 | encodeURIComponent(value), 265 | formatOptions(options), 266 | ].join(''); 267 | } 268 | 269 | export function getObjectProperty(objectRef, propertyName) { 270 | let value = undefined; 271 | let valueRef = objectRef; 272 | const propNames = propertyName.split('.'); 273 | 274 | for (var i = 0; i < propNames.length; i++) { 275 | const key = propNames[i]; 276 | value = valueRef[key]; 277 | 278 | if (isObject(value)) { 279 | valueRef = valueRef[key]; 280 | } else { 281 | break; 282 | } 283 | } 284 | 285 | return value; 286 | } 287 | -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | "@babel/code-frame@^7.0.0", "@babel/code-frame@^7.8.3": 6 | version "7.8.3" 7 | resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.8.3.tgz#33e25903d7481181534e12ec0a25f16b6fcf419e" 8 | integrity sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g== 9 | dependencies: 10 | "@babel/highlight" "^7.8.3" 11 | 12 | "@babel/core@^7.9.0": 13 | version "7.9.0" 14 | resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.9.0.tgz#ac977b538b77e132ff706f3b8a4dbad09c03c56e" 15 | integrity sha512-kWc7L0fw1xwvI0zi8OKVBuxRVefwGOrKSQMvrQ3dW+bIIavBY3/NpXmpjMy7bQnLgwgzWQZ8TlM57YHpHNHz4w== 16 | dependencies: 17 | "@babel/code-frame" "^7.8.3" 18 | "@babel/generator" "^7.9.0" 19 | "@babel/helper-module-transforms" "^7.9.0" 20 | "@babel/helpers" "^7.9.0" 21 | "@babel/parser" "^7.9.0" 22 | "@babel/template" "^7.8.6" 23 | "@babel/traverse" "^7.9.0" 24 | "@babel/types" "^7.9.0" 25 | convert-source-map "^1.7.0" 26 | debug "^4.1.0" 27 | gensync "^1.0.0-beta.1" 28 | json5 "^2.1.2" 29 | lodash "^4.17.13" 30 | resolve "^1.3.2" 31 | semver "^5.4.1" 32 | source-map "^0.5.0" 33 | 34 | "@babel/generator@^7.9.0", "@babel/generator@^7.9.5": 35 | version "7.9.5" 36 | resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.9.5.tgz#27f0917741acc41e6eaaced6d68f96c3fa9afaf9" 37 | integrity sha512-GbNIxVB3ZJe3tLeDm1HSn2AhuD/mVcyLDpgtLXa5tplmWrJdF/elxB56XNqCuD6szyNkDi6wuoKXln3QeBmCHQ== 38 | dependencies: 39 | "@babel/types" "^7.9.5" 40 | jsesc "^2.5.1" 41 | lodash "^4.17.13" 42 | source-map "^0.5.0" 43 | 44 | "@babel/helper-function-name@^7.9.5": 45 | version "7.9.5" 46 | resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.9.5.tgz#2b53820d35275120e1874a82e5aabe1376920a5c" 47 | integrity sha512-JVcQZeXM59Cd1qanDUxv9fgJpt3NeKUaqBqUEvfmQ+BCOKq2xUgaWZW2hr0dkbyJgezYuplEoh5knmrnS68efw== 48 | dependencies: 49 | "@babel/helper-get-function-arity" "^7.8.3" 50 | "@babel/template" "^7.8.3" 51 | "@babel/types" "^7.9.5" 52 | 53 | "@babel/helper-get-function-arity@^7.8.3": 54 | version "7.8.3" 55 | resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.8.3.tgz#b894b947bd004381ce63ea1db9f08547e920abd5" 56 | integrity sha512-FVDR+Gd9iLjUMY1fzE2SR0IuaJToR4RkCDARVfsBBPSP53GEqSFjD8gNyxg246VUyc/ALRxFaAK8rVG7UT7xRA== 57 | dependencies: 58 | "@babel/types" "^7.8.3" 59 | 60 | "@babel/helper-member-expression-to-functions@^7.8.3": 61 | version "7.8.3" 62 | resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.8.3.tgz#659b710498ea6c1d9907e0c73f206eee7dadc24c" 63 | integrity sha512-fO4Egq88utkQFjbPrSHGmGLFqmrshs11d46WI+WZDESt7Wu7wN2G2Iu+NMMZJFDOVRHAMIkB5SNh30NtwCA7RA== 64 | dependencies: 65 | "@babel/types" "^7.8.3" 66 | 67 | "@babel/helper-module-imports@^7.0.0", "@babel/helper-module-imports@^7.8.3": 68 | version "7.8.3" 69 | resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.8.3.tgz#7fe39589b39c016331b6b8c3f441e8f0b1419498" 70 | integrity sha512-R0Bx3jippsbAEtzkpZ/6FIiuzOURPcMjHp+Z6xPe6DtApDJx+w7UYyOLanZqO8+wKR9G10s/FmHXvxaMd9s6Kg== 71 | dependencies: 72 | "@babel/types" "^7.8.3" 73 | 74 | "@babel/helper-module-transforms@^7.9.0": 75 | version "7.9.0" 76 | resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.9.0.tgz#43b34dfe15961918707d247327431388e9fe96e5" 77 | integrity sha512-0FvKyu0gpPfIQ8EkxlrAydOWROdHpBmiCiRwLkUiBGhCUPRRbVD2/tm3sFr/c/GWFrQ/ffutGUAnx7V0FzT2wA== 78 | dependencies: 79 | "@babel/helper-module-imports" "^7.8.3" 80 | "@babel/helper-replace-supers" "^7.8.6" 81 | "@babel/helper-simple-access" "^7.8.3" 82 | "@babel/helper-split-export-declaration" "^7.8.3" 83 | "@babel/template" "^7.8.6" 84 | "@babel/types" "^7.9.0" 85 | lodash "^4.17.13" 86 | 87 | "@babel/helper-optimise-call-expression@^7.8.3": 88 | version "7.8.3" 89 | resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.8.3.tgz#7ed071813d09c75298ef4f208956006b6111ecb9" 90 | integrity sha512-Kag20n86cbO2AvHca6EJsvqAd82gc6VMGule4HwebwMlwkpXuVqrNRj6CkCV2sKxgi9MyAUnZVnZ6lJ1/vKhHQ== 91 | dependencies: 92 | "@babel/types" "^7.8.3" 93 | 94 | "@babel/helper-replace-supers@^7.8.6": 95 | version "7.8.6" 96 | resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.8.6.tgz#5ada744fd5ad73203bf1d67459a27dcba67effc8" 97 | integrity sha512-PeMArdA4Sv/Wf4zXwBKPqVj7n9UF/xg6slNRtZW84FM7JpE1CbG8B612FyM4cxrf4fMAMGO0kR7voy1ForHHFA== 98 | dependencies: 99 | "@babel/helper-member-expression-to-functions" "^7.8.3" 100 | "@babel/helper-optimise-call-expression" "^7.8.3" 101 | "@babel/traverse" "^7.8.6" 102 | "@babel/types" "^7.8.6" 103 | 104 | "@babel/helper-simple-access@^7.8.3": 105 | version "7.8.3" 106 | resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.8.3.tgz#7f8109928b4dab4654076986af575231deb639ae" 107 | integrity sha512-VNGUDjx5cCWg4vvCTR8qQ7YJYZ+HBjxOgXEl7ounz+4Sn7+LMD3CFrCTEU6/qXKbA2nKg21CwhhBzO0RpRbdCw== 108 | dependencies: 109 | "@babel/template" "^7.8.3" 110 | "@babel/types" "^7.8.3" 111 | 112 | "@babel/helper-split-export-declaration@^7.8.3": 113 | version "7.8.3" 114 | resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.8.3.tgz#31a9f30070f91368a7182cf05f831781065fc7a9" 115 | integrity sha512-3x3yOeyBhW851hroze7ElzdkeRXQYQbFIb7gLK1WQYsw2GWDay5gAJNw1sWJ0VFP6z5J1whqeXH/WCdCjZv6dA== 116 | dependencies: 117 | "@babel/types" "^7.8.3" 118 | 119 | "@babel/helper-validator-identifier@^7.9.0", "@babel/helper-validator-identifier@^7.9.5": 120 | version "7.9.5" 121 | resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.9.5.tgz#90977a8e6fbf6b431a7dc31752eee233bf052d80" 122 | integrity sha512-/8arLKUFq882w4tWGj9JYzRpAlZgiWUJ+dtteNTDqrRBz9Iguck9Rn3ykuBDoUwh2TO4tSAJlrxDUOXWklJe4g== 123 | 124 | "@babel/helpers@^7.9.0": 125 | version "7.9.2" 126 | resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.9.2.tgz#b42a81a811f1e7313b88cba8adc66b3d9ae6c09f" 127 | integrity sha512-JwLvzlXVPjO8eU9c/wF9/zOIN7X6h8DYf7mG4CiFRZRvZNKEF5dQ3H3V+ASkHoIB3mWhatgl5ONhyqHRI6MppA== 128 | dependencies: 129 | "@babel/template" "^7.8.3" 130 | "@babel/traverse" "^7.9.0" 131 | "@babel/types" "^7.9.0" 132 | 133 | "@babel/highlight@^7.8.3": 134 | version "7.9.0" 135 | resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.9.0.tgz#4e9b45ccb82b79607271b2979ad82c7b68163079" 136 | integrity sha512-lJZPilxX7Op3Nv/2cvFdnlepPXDxi29wxteT57Q965oc5R9v86ztx0jfxVrTcBk8C2kcPkkDa2Z4T3ZsPPVWsQ== 137 | dependencies: 138 | "@babel/helper-validator-identifier" "^7.9.0" 139 | chalk "^2.0.0" 140 | js-tokens "^4.0.0" 141 | 142 | "@babel/parser@^7.8.6", "@babel/parser@^7.9.0": 143 | version "7.9.4" 144 | resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.9.4.tgz#68a35e6b0319bbc014465be43828300113f2f2e8" 145 | integrity sha512-bC49otXX6N0/VYhgOMh4gnP26E9xnDZK3TmbNpxYzzz9BQLBosQwfyOe9/cXUU3txYhTzLCbcqd5c8y/OmCjHA== 146 | 147 | "@babel/template@^7.8.3", "@babel/template@^7.8.6": 148 | version "7.8.6" 149 | resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.8.6.tgz#86b22af15f828dfb086474f964dcc3e39c43ce2b" 150 | integrity sha512-zbMsPMy/v0PWFZEhQJ66bqjhH+z0JgMoBWuikXybgG3Gkd/3t5oQ1Rw2WQhnSrsOmsKXnZOx15tkC4qON/+JPg== 151 | dependencies: 152 | "@babel/code-frame" "^7.8.3" 153 | "@babel/parser" "^7.8.6" 154 | "@babel/types" "^7.8.6" 155 | 156 | "@babel/traverse@^7.8.6", "@babel/traverse@^7.9.0": 157 | version "7.9.5" 158 | resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.9.5.tgz#6e7c56b44e2ac7011a948c21e283ddd9d9db97a2" 159 | integrity sha512-c4gH3jsvSuGUezlP6rzSJ6jf8fYjLj3hsMZRx/nX0h+fmHN0w+ekubRrHPqnMec0meycA2nwCsJ7dC8IPem2FQ== 160 | dependencies: 161 | "@babel/code-frame" "^7.8.3" 162 | "@babel/generator" "^7.9.5" 163 | "@babel/helper-function-name" "^7.9.5" 164 | "@babel/helper-split-export-declaration" "^7.8.3" 165 | "@babel/parser" "^7.9.0" 166 | "@babel/types" "^7.9.5" 167 | debug "^4.1.0" 168 | globals "^11.1.0" 169 | lodash "^4.17.13" 170 | 171 | "@babel/types@^7.8.3", "@babel/types@^7.8.6", "@babel/types@^7.9.0", "@babel/types@^7.9.5": 172 | version "7.9.5" 173 | resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.9.5.tgz#89231f82915a8a566a703b3b20133f73da6b9444" 174 | integrity sha512-XjnvNqenk818r5zMaba+sLQjnbda31UfUURv3ei0qPQw4u+j2jMyJ5b11y8ZHYTRSI3NnInQkkkRT4fLqqPdHg== 175 | dependencies: 176 | "@babel/helper-validator-identifier" "^7.9.5" 177 | lodash "^4.17.13" 178 | to-fast-properties "^2.0.0" 179 | 180 | "@rollup/plugin-buble@^0.21.3": 181 | version "0.21.3" 182 | resolved "https://registry.yarnpkg.com/@rollup/plugin-buble/-/plugin-buble-0.21.3.tgz#1649a915b1d051a4f430d40e7734a7f67a69b33e" 183 | integrity sha512-Iv8cCuFPnMdqV4pcyU+OrfjOfagPArRQ1PyQjx5KgHk3dARedI+8PNTLSMpJts0lQJr8yF2pAU4GxpxCBJ9HYw== 184 | dependencies: 185 | "@rollup/pluginutils" "^3.0.8" 186 | "@types/buble" "^0.19.2" 187 | buble "^0.20.0" 188 | 189 | "@rollup/pluginutils@^3.0.8": 190 | version "3.0.9" 191 | resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-3.0.9.tgz#aa6adca2c45e5a1b950103a999e3cddfe49fd775" 192 | integrity sha512-TLZavlfPAZYI7v33wQh4mTP6zojne14yok3DNSLcjoG/Hirxfkonn6icP5rrNWRn8nZsirJBFFpijVOJzkUHDg== 193 | dependencies: 194 | "@types/estree" "0.0.39" 195 | estree-walker "^1.0.1" 196 | micromatch "^4.0.2" 197 | 198 | "@types/buble@^0.19.2": 199 | version "0.19.2" 200 | resolved "https://registry.yarnpkg.com/@types/buble/-/buble-0.19.2.tgz#a4289d20b175b3c206aaad80caabdabe3ecdfdd1" 201 | integrity sha512-uUD8zIfXMKThmFkahTXDGI3CthFH1kMg2dOm3KLi4GlC5cbARA64bEcUMbbWdWdE73eoc/iBB9PiTMqH0dNS2Q== 202 | dependencies: 203 | magic-string "^0.25.0" 204 | 205 | "@types/estree@0.0.39": 206 | version "0.0.39" 207 | resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.39.tgz#e177e699ee1b8c22d23174caaa7422644389509f" 208 | integrity sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw== 209 | 210 | acorn-dynamic-import@^4.0.0: 211 | version "4.0.0" 212 | resolved "https://registry.yarnpkg.com/acorn-dynamic-import/-/acorn-dynamic-import-4.0.0.tgz#482210140582a36b83c3e342e1cfebcaa9240948" 213 | integrity sha512-d3OEjQV4ROpoflsnUA8HozoIR504TFxNivYEUi6uwz0IYhBkTDXGuWlNdMtybRt3nqVx/L6XqMt0FxkXuWKZhw== 214 | 215 | acorn-jsx@^5.2.0: 216 | version "5.2.0" 217 | resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.2.0.tgz#4c66069173d6fdd68ed85239fc256226182b2ebe" 218 | integrity sha512-HiUX/+K2YpkpJ+SzBffkM/AQ2YE03S0U1kjTLVpoJdhZMOWy8qvXVN9JdLqv2QsaQ6MPYQIuNmwD8zOiYUofLQ== 219 | 220 | acorn@^6.1.1: 221 | version "6.1.1" 222 | resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.1.1.tgz#7d25ae05bb8ad1f9b699108e1094ecd7884adc1f" 223 | integrity sha512-jPTiwtOxaHNaAPg/dmrJ/beuzLRnXtB0kQPQ8JpotKJgTB6rX6c8mlf315941pyjBSaPg8NHXS9fhP4u17DpGA== 224 | 225 | acorn@^6.4.1: 226 | version "6.4.1" 227 | resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.4.1.tgz#531e58ba3f51b9dacb9a6646ca4debf5b14ca474" 228 | integrity sha512-ZVA9k326Nwrj3Cj9jlh3wGFutC2ZornPNARZwsNYqQYgN0EsV2d53w5RN/co65Ohn4sUAUtb1rSUAOD6XN9idA== 229 | 230 | ajv@^6.10.0: 231 | version "6.10.0" 232 | resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.10.0.tgz#90d0d54439da587cd7e843bfb7045f50bd22bdf1" 233 | integrity sha512-nffhOpkymDECQyR0mnsUtoCE8RlX38G0rYP+wgLWFyZuUyuuojSSvi/+euOiQBIn63whYwYVIIH1TvE3tu4OEg== 234 | dependencies: 235 | fast-deep-equal "^2.0.1" 236 | fast-json-stable-stringify "^2.0.0" 237 | json-schema-traverse "^0.4.1" 238 | uri-js "^4.2.2" 239 | 240 | ansi-styles@^3.2.1: 241 | version "3.2.1" 242 | resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" 243 | integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== 244 | dependencies: 245 | color-convert "^1.9.0" 246 | 247 | axios@^0.18.0: 248 | version "0.18.0" 249 | resolved "https://registry.yarnpkg.com/axios/-/axios-0.18.0.tgz#32d53e4851efdc0a11993b6cd000789d70c05102" 250 | integrity sha1-MtU+SFHv3AoRmTts0AB4nXDAUQI= 251 | dependencies: 252 | follow-redirects "^1.3.0" 253 | is-buffer "^1.1.5" 254 | 255 | braces@^3.0.1: 256 | version "3.0.2" 257 | resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" 258 | integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== 259 | dependencies: 260 | fill-range "^7.0.1" 261 | 262 | buble@^0.20.0: 263 | version "0.20.0" 264 | resolved "https://registry.yarnpkg.com/buble/-/buble-0.20.0.tgz#a143979a8d968b7f76b57f38f2e7ce7cfe938d1f" 265 | integrity sha512-/1gnaMQE8xvd5qsNBl+iTuyjJ9XxeaVxAMF86dQ4EyxFJOZtsgOS8Ra+7WHgZTam5IFDtt4BguN0sH0tVTKrOw== 266 | dependencies: 267 | acorn "^6.4.1" 268 | acorn-dynamic-import "^4.0.0" 269 | acorn-jsx "^5.2.0" 270 | chalk "^2.4.2" 271 | magic-string "^0.25.7" 272 | minimist "^1.2.5" 273 | regexpu-core "4.5.4" 274 | 275 | chalk@^2.0.0, chalk@^2.4.2: 276 | version "2.4.2" 277 | resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" 278 | integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== 279 | dependencies: 280 | ansi-styles "^3.2.1" 281 | escape-string-regexp "^1.0.5" 282 | supports-color "^5.3.0" 283 | 284 | color-convert@^1.9.0: 285 | version "1.9.3" 286 | resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" 287 | integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== 288 | dependencies: 289 | color-name "1.1.3" 290 | 291 | color-name@1.1.3: 292 | version "1.1.3" 293 | resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" 294 | integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= 295 | 296 | commander@~2.20.3: 297 | version "2.20.3" 298 | resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" 299 | integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== 300 | 301 | convert-source-map@^1.7.0: 302 | version "1.7.0" 303 | resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.7.0.tgz#17a2cb882d7f77d3490585e2ce6c524424a3a442" 304 | integrity sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA== 305 | dependencies: 306 | safe-buffer "~5.1.1" 307 | 308 | debug@^3.2.6: 309 | version "3.2.6" 310 | resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" 311 | integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ== 312 | dependencies: 313 | ms "^2.1.1" 314 | 315 | debug@^4.1.0: 316 | version "4.1.1" 317 | resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791" 318 | integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw== 319 | dependencies: 320 | ms "^2.1.1" 321 | 322 | escape-string-regexp@^1.0.5: 323 | version "1.0.5" 324 | resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" 325 | integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= 326 | 327 | estree-walker@^0.6.1: 328 | version "0.6.1" 329 | resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-0.6.1.tgz#53049143f40c6eb918b23671d1fe3219f3a1b362" 330 | integrity sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w== 331 | 332 | estree-walker@^1.0.1: 333 | version "1.0.1" 334 | resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-1.0.1.tgz#31bc5d612c96b704106b477e6dd5d8aa138cb700" 335 | integrity sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg== 336 | 337 | fast-deep-equal@^2.0.1: 338 | version "2.0.1" 339 | resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49" 340 | integrity sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk= 341 | 342 | fast-json-stable-stringify@^2.0.0: 343 | version "2.0.0" 344 | resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" 345 | integrity sha1-1RQsDK7msRifh9OnYREGT4bIu/I= 346 | 347 | fill-range@^7.0.1: 348 | version "7.0.1" 349 | resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" 350 | integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== 351 | dependencies: 352 | to-regex-range "^5.0.1" 353 | 354 | follow-redirects@^1.3.0: 355 | version "1.7.0" 356 | resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.7.0.tgz#489ebc198dc0e7f64167bd23b03c4c19b5784c76" 357 | integrity sha512-m/pZQy4Gj287eNy94nivy5wchN3Kp+Q5WgUPNy5lJSZ3sgkVKSYV/ZChMAQVIgx1SqfZ2zBZtPA2YlXIWxxJOQ== 358 | dependencies: 359 | debug "^3.2.6" 360 | 361 | fsevents@~2.1.2: 362 | version "2.1.2" 363 | resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.1.2.tgz#4c0a1fb34bc68e543b4b82a9ec392bfbda840805" 364 | integrity sha512-R4wDiBwZ0KzpgOWetKDug1FZcYhqYnUYKtfZYt4mD5SBz76q0KR4Q9o7GIPamsVPGmW3EYPPJ0dOOjvx32ldZA== 365 | 366 | gensync@^1.0.0-beta.1: 367 | version "1.0.0-beta.1" 368 | resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.1.tgz#58f4361ff987e5ff6e1e7a210827aa371eaac269" 369 | integrity sha512-r8EC6NO1sngH/zdD9fiRDLdcgnbayXah+mLgManTaIZJqEC1MZstmnox8KpnI2/fxQwrp5OpCOYWLp4rBl4Jcg== 370 | 371 | globals@^11.1.0: 372 | version "11.12.0" 373 | resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" 374 | integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== 375 | 376 | has-flag@^3.0.0: 377 | version "3.0.0" 378 | resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" 379 | integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= 380 | 381 | is-buffer@^1.1.5: 382 | version "1.1.6" 383 | resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" 384 | integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== 385 | 386 | is-number@^7.0.0: 387 | version "7.0.0" 388 | resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" 389 | integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== 390 | 391 | jest-worker@^24.0.0: 392 | version "24.9.0" 393 | resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-24.9.0.tgz#5dbfdb5b2d322e98567898238a9697bcce67b3e5" 394 | integrity sha512-51PE4haMSXcHohnSMdM42anbvZANYTqMrr52tVKPqqsPJMzoP6FYYDVqahX/HrAoKEKz3uUPzSvKs9A3qR4iVw== 395 | dependencies: 396 | merge-stream "^2.0.0" 397 | supports-color "^6.1.0" 398 | 399 | js-tokens@^4.0.0: 400 | version "4.0.0" 401 | resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" 402 | integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== 403 | 404 | jsesc@^2.5.1: 405 | version "2.5.2" 406 | resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" 407 | integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== 408 | 409 | jsesc@~0.5.0: 410 | version "0.5.0" 411 | resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" 412 | integrity sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0= 413 | 414 | json-schema-traverse@^0.4.1: 415 | version "0.4.1" 416 | resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" 417 | integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== 418 | 419 | json5@^2.1.2: 420 | version "2.1.3" 421 | resolved "https://registry.yarnpkg.com/json5/-/json5-2.1.3.tgz#c9b0f7fa9233bfe5807fe66fcf3a5617ed597d43" 422 | integrity sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA== 423 | dependencies: 424 | minimist "^1.2.5" 425 | 426 | lodash._reinterpolate@^3.0.0: 427 | version "3.0.0" 428 | resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d" 429 | integrity sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0= 430 | 431 | lodash.template@^4.4.0: 432 | version "4.5.0" 433 | resolved "https://registry.yarnpkg.com/lodash.template/-/lodash.template-4.5.0.tgz#f976195cf3f347d0d5f52483569fe8031ccce8ab" 434 | integrity sha512-84vYFxIkmidUiFxidA/KjjH9pAycqW+h980j7Fuz5qxRtO9pgB7MDFTdys1N7A5mcucRiDyEq4fusljItR1T/A== 435 | dependencies: 436 | lodash._reinterpolate "^3.0.0" 437 | lodash.templatesettings "^4.0.0" 438 | 439 | lodash.templatesettings@^4.0.0: 440 | version "4.2.0" 441 | resolved "https://registry.yarnpkg.com/lodash.templatesettings/-/lodash.templatesettings-4.2.0.tgz#e481310f049d3cf6d47e912ad09313b154f0fb33" 442 | integrity sha512-stgLz+i3Aa9mZgnjr/O+v9ruKZsPsndy7qPZOchbqk2cnTU1ZaldKK+v7m54WoKIyxiuMZTKT2H81F8BeAc3ZQ== 443 | dependencies: 444 | lodash._reinterpolate "^3.0.0" 445 | 446 | lodash@^4.17.13: 447 | version "4.17.15" 448 | resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548" 449 | integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A== 450 | 451 | magic-string@^0.25.0, magic-string@^0.25.7: 452 | version "0.25.7" 453 | resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.25.7.tgz#3f497d6fd34c669c6798dcb821f2ef31f5445051" 454 | integrity sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA== 455 | dependencies: 456 | sourcemap-codec "^1.4.4" 457 | 458 | merge-stream@^2.0.0: 459 | version "2.0.0" 460 | resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" 461 | integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== 462 | 463 | micromatch@^4.0.2: 464 | version "4.0.2" 465 | resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.2.tgz#4fcb0999bf9fbc2fcbdd212f6d629b9a56c39259" 466 | integrity sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q== 467 | dependencies: 468 | braces "^3.0.1" 469 | picomatch "^2.0.5" 470 | 471 | minimist@^1.2.5: 472 | version "1.2.5" 473 | resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" 474 | integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== 475 | 476 | ms@^2.1.1: 477 | version "2.1.1" 478 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" 479 | integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg== 480 | 481 | path-parse@^1.0.6: 482 | version "1.0.6" 483 | resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c" 484 | integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw== 485 | 486 | picomatch@^2.0.5: 487 | version "2.2.2" 488 | resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.2.tgz#21f333e9b6b8eaff02468f5146ea406d345f4dad" 489 | integrity sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg== 490 | 491 | punycode@^2.1.0: 492 | version "2.1.1" 493 | resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" 494 | integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== 495 | 496 | regenerate-unicode-properties@^8.0.2: 497 | version "8.2.0" 498 | resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-8.2.0.tgz#e5de7111d655e7ba60c057dbe9ff37c87e65cdec" 499 | integrity sha512-F9DjY1vKLo/tPePDycuH3dn9H1OTPIkVD9Kz4LODu+F2C75mgjAJ7x/gwy6ZcSNRAAkhNlJSOHRe8k3p+K9WhA== 500 | dependencies: 501 | regenerate "^1.4.0" 502 | 503 | regenerate@^1.4.0: 504 | version "1.4.0" 505 | resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.0.tgz#4a856ec4b56e4077c557589cae85e7a4c8869a11" 506 | integrity sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg== 507 | 508 | regexpu-core@4.5.4: 509 | version "4.5.4" 510 | resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-4.5.4.tgz#080d9d02289aa87fe1667a4f5136bc98a6aebaae" 511 | integrity sha512-BtizvGtFQKGPUcTy56o3nk1bGRp4SZOTYrDtGNlqCQufptV5IkkLN6Emw+yunAJjzf+C9FQFtvq7IoA3+oMYHQ== 512 | dependencies: 513 | regenerate "^1.4.0" 514 | regenerate-unicode-properties "^8.0.2" 515 | regjsgen "^0.5.0" 516 | regjsparser "^0.6.0" 517 | unicode-match-property-ecmascript "^1.0.4" 518 | unicode-match-property-value-ecmascript "^1.1.0" 519 | 520 | regjsgen@^0.5.0: 521 | version "0.5.1" 522 | resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.5.1.tgz#48f0bf1a5ea205196929c0d9798b42d1ed98443c" 523 | integrity sha512-5qxzGZjDs9w4tzT3TPhCJqWdCc3RLYwy9J2NB0nm5Lz+S273lvWcpjaTGHsT1dc6Hhfq41uSEOw8wBmxrKOuyg== 524 | 525 | regjsparser@^0.6.0: 526 | version "0.6.4" 527 | resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.6.4.tgz#a769f8684308401a66e9b529d2436ff4d0666272" 528 | integrity sha512-64O87/dPDgfk8/RQqC4gkZoGyyWFIEUTTh80CU6CWuK5vkCGyekIx+oKcEIYtP/RAxSQltCZHCNu/mdd7fqlJw== 529 | dependencies: 530 | jsesc "~0.5.0" 531 | 532 | resolve@^1.3.2: 533 | version "1.16.1" 534 | resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.16.1.tgz#49fac5d8bacf1fd53f200fa51247ae736175832c" 535 | integrity sha512-rmAglCSqWWMrrBv/XM6sW0NuRFiKViw/W4d9EbC4pt+49H8JwHy+mcGmALTEg504AUDcLTvb1T2q3E9AnmY+ig== 536 | dependencies: 537 | path-parse "^1.0.6" 538 | 539 | rollup-plugin-babel@^4.4.0: 540 | version "4.4.0" 541 | resolved "https://registry.yarnpkg.com/rollup-plugin-babel/-/rollup-plugin-babel-4.4.0.tgz#d15bd259466a9d1accbdb2fe2fff17c52d030acb" 542 | integrity sha512-Lek/TYp1+7g7I+uMfJnnSJ7YWoD58ajo6Oarhlex7lvUce+RCKRuGRSgztDO3/MF/PuGKmUL5iTHKf208UNszw== 543 | dependencies: 544 | "@babel/helper-module-imports" "^7.0.0" 545 | rollup-pluginutils "^2.8.1" 546 | 547 | rollup-plugin-banner@^0.2.1: 548 | version "0.2.1" 549 | resolved "https://registry.yarnpkg.com/rollup-plugin-banner/-/rollup-plugin-banner-0.2.1.tgz#f62f26c468530ecea16263da83175079625f9c6f" 550 | integrity sha512-Bs1uIPCsGpKIkNOwmBsCqn+dJ/xaojWk9PNlvd+1MEScddr1yUQlO6McAXi72wJyNWYL+9u9EI2JAZMpLRH92w== 551 | dependencies: 552 | lodash.template "^4.4.0" 553 | 554 | rollup-plugin-uglify@^6.0.4: 555 | version "6.0.4" 556 | resolved "https://registry.yarnpkg.com/rollup-plugin-uglify/-/rollup-plugin-uglify-6.0.4.tgz#65a0959d91586627f1e46a7db966fd504ec6c4e6" 557 | integrity sha512-ddgqkH02klveu34TF0JqygPwZnsbhHVI6t8+hGTcYHngPkQb5MIHI0XiztXIN/d6V9j+efwHAqEL7LspSxQXGw== 558 | dependencies: 559 | "@babel/code-frame" "^7.0.0" 560 | jest-worker "^24.0.0" 561 | serialize-javascript "^2.1.2" 562 | uglify-js "^3.4.9" 563 | 564 | rollup-pluginutils@^2.8.1: 565 | version "2.8.2" 566 | resolved "https://registry.yarnpkg.com/rollup-pluginutils/-/rollup-pluginutils-2.8.2.tgz#72f2af0748b592364dbd3389e600e5a9444a351e" 567 | integrity sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ== 568 | dependencies: 569 | estree-walker "^0.6.1" 570 | 571 | rollup@^2.6.1: 572 | version "2.6.1" 573 | resolved "https://registry.yarnpkg.com/rollup/-/rollup-2.6.1.tgz#8354e67caa7b8bf24c2488d9e2f64da2be62eebe" 574 | integrity sha512-1RhFDRJeg027YjBO6+JxmVWkEZY0ASztHhoEUEWxOwkh4mjO58TFD6Uo7T7Y3FbmDpRTfKhM5NVxJyimCn0Elg== 575 | optionalDependencies: 576 | fsevents "~2.1.2" 577 | 578 | safe-buffer@~5.1.1: 579 | version "5.1.2" 580 | resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" 581 | integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== 582 | 583 | semver@^5.4.1: 584 | version "5.7.1" 585 | resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" 586 | integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== 587 | 588 | serialize-javascript@^2.1.2: 589 | version "2.1.2" 590 | resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-2.1.2.tgz#ecec53b0e0317bdc95ef76ab7074b7384785fa61" 591 | integrity sha512-rs9OggEUF0V4jUSecXazOYsLfu7OGK2qIn3c7IPBiffz32XniEp/TX9Xmc9LQfK2nQ2QKHvZ2oygKUGU0lG4jQ== 592 | 593 | source-map@^0.5.0: 594 | version "0.5.7" 595 | resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" 596 | integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= 597 | 598 | sourcemap-codec@^1.4.4: 599 | version "1.4.8" 600 | resolved "https://registry.yarnpkg.com/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz#ea804bd94857402e6992d05a38ef1ae35a9ab4c4" 601 | integrity sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA== 602 | 603 | supports-color@^5.3.0: 604 | version "5.5.0" 605 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" 606 | integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== 607 | dependencies: 608 | has-flag "^3.0.0" 609 | 610 | supports-color@^6.1.0: 611 | version "6.1.0" 612 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-6.1.0.tgz#0764abc69c63d5ac842dd4867e8d025e880df8f3" 613 | integrity sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ== 614 | dependencies: 615 | has-flag "^3.0.0" 616 | 617 | to-fast-properties@^2.0.0: 618 | version "2.0.0" 619 | resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" 620 | integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4= 621 | 622 | to-regex-range@^5.0.1: 623 | version "5.0.1" 624 | resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" 625 | integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== 626 | dependencies: 627 | is-number "^7.0.0" 628 | 629 | uglify-js@^3.4.9, uglify-js@^3.9.1: 630 | version "3.9.1" 631 | resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.9.1.tgz#a56a71c8caa2d36b5556cc1fd57df01ae3491539" 632 | integrity sha512-JUPoL1jHsc9fOjVFHdQIhqEEJsQvfKDjlubcCilu8U26uZ73qOg8VsN8O1jbuei44ZPlwL7kmbAdM4tzaUvqnA== 633 | dependencies: 634 | commander "~2.20.3" 635 | 636 | unicode-canonical-property-names-ecmascript@^1.0.4: 637 | version "1.0.4" 638 | resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz#2619800c4c825800efdd8343af7dd9933cbe2818" 639 | integrity sha512-jDrNnXWHd4oHiTZnx/ZG7gtUTVp+gCcTTKr8L0HjlwphROEW3+Him+IpvC+xcJEFegapiMZyZe02CyuOnRmbnQ== 640 | 641 | unicode-match-property-ecmascript@^1.0.4: 642 | version "1.0.4" 643 | resolved "https://registry.yarnpkg.com/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-1.0.4.tgz#8ed2a32569961bce9227d09cd3ffbb8fed5f020c" 644 | integrity sha512-L4Qoh15vTfntsn4P1zqnHulG0LdXgjSO035fEpdtp6YxXhMT51Q6vgM5lYdG/5X3MjS+k/Y9Xw4SFCY9IkR0rg== 645 | dependencies: 646 | unicode-canonical-property-names-ecmascript "^1.0.4" 647 | unicode-property-aliases-ecmascript "^1.0.4" 648 | 649 | unicode-match-property-value-ecmascript@^1.1.0: 650 | version "1.2.0" 651 | resolved "https://registry.yarnpkg.com/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.2.0.tgz#0d91f600eeeb3096aa962b1d6fc88876e64ea531" 652 | integrity sha512-wjuQHGQVofmSJv1uVISKLE5zO2rNGzM/KCYZch/QQvez7C1hUhBIuZ701fYXExuufJFMPhv2SyL8CyoIfMLbIQ== 653 | 654 | unicode-property-aliases-ecmascript@^1.0.4: 655 | version "1.1.0" 656 | resolved "https://registry.yarnpkg.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.1.0.tgz#dd57a99f6207bedff4628abefb94c50db941c8f4" 657 | integrity sha512-PqSoPh/pWetQ2phoj5RLiaqIk4kCNwoV3CI+LfGmWLKI3rE3kl1h59XpX2BjgDrmbxD9ARtQobPGU1SguCYuQg== 658 | 659 | uri-js@^4.2.2: 660 | version "4.2.2" 661 | resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0" 662 | integrity sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ== 663 | dependencies: 664 | punycode "^2.1.0" 665 | 666 | vue-axios@^2.1.4: 667 | version "2.1.4" 668 | resolved "https://registry.yarnpkg.com/vue-axios/-/vue-axios-2.1.4.tgz#a9d298f7e876f9a87feb336b37adcbce34ff9f9f" 669 | integrity sha512-DS8Q+WFT3i7nS0aZ/NMmTPf2yhbtlXhj4QEZmY69au/BshsGzGjC6dXaniZaPQlErP3J3Sv1HtQ4RVrXaUTkxA== 670 | 671 | vue@^2.6.10: 672 | version "2.6.10" 673 | resolved "https://registry.yarnpkg.com/vue/-/vue-2.6.10.tgz#a72b1a42a4d82a721ea438d1b6bf55e66195c637" 674 | integrity sha512-ImThpeNU9HbdZL3utgMCq0oiMzAkt1mcgy3/E6zWC/G6AaQoeuFdsl9nDhTDU3X1R6FK7nsIUuRACVcjI+A2GQ== 675 | --------------------------------------------------------------------------------