├── .DS_Store
├── .babelrc
├── .coveralls.yml
├── .editorconfig
├── .eslintignore
├── .eslintrc
├── .gitignore
├── .npmignore
├── .tern-project
├── .travis.yml
├── README.md
├── bower.json
├── build
└── build.js
├── dist
├── vue-social-auth.common.js
├── vue-social-auth.es2017.js
├── vue-social-auth.js
└── vue-social-auth.min.js
├── gulpfile.js
├── nuxt
├── index.js
└── plugin.template.js
├── package.json
└── src
├── authenticate.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
/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/diadal/vue-social-auth/2eadbcf6a038f36e9f22e7393e621965cd3a0da5/.DS_Store
--------------------------------------------------------------------------------
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | [
4 | "es2017",
5 | {
6 | "modules": false
7 | }
8 | ]
9 | ],
10 | "plugins": ["external-helpers"]
11 | }
--------------------------------------------------------------------------------
/.coveralls.yml:
--------------------------------------------------------------------------------
1 | repo_token: G9JVOf8Hp3YbCmoFPU2ILSW03p2FbRMKn
--------------------------------------------------------------------------------
/.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 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /node_modules
2 | /package-lock.json
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
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 |
--------------------------------------------------------------------------------
/.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 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - "node"
4 | - "13"
5 | - "12"
6 | - "11"
7 | - "10"
8 | - "8"
9 | - "6"
10 | script: node src/index.js
11 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](https://snyk.io/test/github/diadal/vue-social-auth)
2 |
3 | **NOTE:** The new Version works better
4 |
5 | ## ♻️ [Update Version Universal-Social-Auth](https://github.com/diadal/universal-social-auth)
6 |
7 | # Laravel vue-social-auth
8 |
9 | **vue-social-auth** is easily configurable solution for [Vue.js](https://vuejs.org/) & [Laravel](https://laravel.com/) with Socialite that provides Social login using Github, Facebook, Google, Vkontakte and other OAuth providers.
10 |
11 |
12 | 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.
13 |
14 | 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).
15 |
16 | **WARNING:** Default request library is `axios` using `vue-axios` wrapper plugin.
17 |
18 | **NOTE:** It also work with any Php with `Socialite`
19 |
20 | ## Supported OAuth providers and configurations
21 |
22 | ## Installation
23 |
24 | ## firstly install `Socialite`
25 |
26 | **NOTE:** make sure you config your `Socialite` configuration data in `services.php` & `.env` for more details
27 | check [https://socialiteproviders.netlify.com/](https://socialiteproviders.netlify.com/)
28 |
29 | ```bash
30 | composer require laravel/socialite
31 |
32 | ```
33 | ## Next install vue-social-auth
34 |
35 | ```bash
36 | npm install vue-social-auth
37 | ```
38 |
39 | ## Usage
40 | ```javascript
41 | import Vue from 'vue'
42 | import axios from 'axios';
43 | import VueAxios from 'vue-axios'
44 | import VueSocialauth from 'vue-social-auth'
45 |
46 | Vue.use(VueAxios, axios)
47 | Vue.use(VueSocialauth, {
48 |
49 | providers: {
50 | github: {
51 | clientId: '',
52 | redirectUri: '/auth/github/callback' // Your client app URL
53 | }
54 | }
55 | })
56 | ```
57 |
58 | ```html
59 |
60 |
61 |
62 |
63 |
64 | ```
65 |
66 | ## ♻️ Usage with Nuxt.js
67 |
68 | Add `vue-social-auth/nuxt` to modules section of `nuxt.config.js`
69 |
70 | Module automatically add to $auth or property selected
71 |
72 | ```js
73 | {
74 | modules: [
75 | // Optionally passing options in module configuration
76 | ['vue-social-auth/nuxt', {
77 | property: '$auth', // Optional property if the $auth property is being used by another module
78 | providers: {
79 | github: {
80 | clientId: '',
81 | redirectUri: '/auth/github/callback' // Your client app URL
82 | }
83 | }
84 | }]
85 | ],
86 |
87 | // Optionally passing options in module top level configuration
88 | vueSocialAuth: {
89 | property: '$auth'
90 | providers: {
91 | // ...
92 | }
93 | }
94 | }
95 | ```
96 |
97 |
98 | ### View Component
99 | ```javascript
100 |
141 | ```
142 |
143 | #### Vue Router
144 |
145 | ```javascript
146 |
147 | {
148 | path: '/auth/:provider/callback',
149 | component: {
150 | template: '
'
151 | }
152 | },
153 |
154 | ```
155 |
156 | ### Vue is Done let move to backend config `Laravel` with `Socialite`
157 |
158 | #### Laravel Router
159 |
160 | ```php
161 |
162 | Route::post('sociallogin/{provider}', 'Auth\AuthController@SocialSignup');
163 | Route::get('auth/{provider}/callback', 'OutController@index')->where('provider', '.*');
164 |
165 |
166 | ```
167 |
168 | #### OutController
169 |
170 | ```php
171 |
172 | stateless()->user();
226 |
227 | return response()->json($user);
228 | }
229 |
230 | }
231 |
232 |
233 | ```
234 |
235 |
236 | #### services.php
237 |
238 | ```php
239 |
240 | [
247 | 'client_id' => env('TWITTER_ID'),
248 | 'client_secret' => env('TWITTER_SECRET'),
249 | 'redirect' => env('TWITTER_URL'),
250 | ],
251 |
252 | 'facebook' => [
253 | 'client_id' => env('FACEBOOK_ID'),
254 | 'client_secret' => env('FACEBOOK_SECRET'),
255 | 'redirect' => env('FACEBOOK_URL'),
256 | ],
257 |
258 | 'github' => [
259 | 'client_id' => env('GITHUB_ID'),
260 | 'client_secret' => env('GITHUB_SECRET'),
261 | 'redirect' => env('GITHUB_URL'),
262 | ],
263 |
264 | 'google' => [
265 | 'client_id' => env('GOOGLE_ID'),
266 | 'client_secret' => env('GOOGLE_SECRET'),
267 | 'redirect' => env('GOOGLE_URL'),
268 | ],
269 |
270 | 'vkontakte' => [
271 | 'client_id' => env('VKONTAKTE_KEY'),
272 | 'client_secret' => env('VKONTAKTE_SECRET'),
273 | 'redirect' => env('VKONTAKTE_REDIRECT_URI'),
274 | ],
275 | ];
276 |
277 |
278 | ```
279 |
280 | #### .env
281 |
282 | ```text
283 |
284 | TWITTER_ID=Your ID
285 | TWITTER_SECRET=Your Secret
286 | TWITTER_URL=https://example.com/auth/twitter/callback
287 |
288 | FACEBOOK_ID=Your ID
289 | FACEBOOK_SECRET=Your Secret
290 | FACEBOOK_URL=https://example.com/auth/facebook/callback
291 |
292 | GITHUB_ID=Your ID
293 | GITHUB_SECRET=Your Secret
294 | GITHUB_URL=https://example.com/auth/github/callback
295 |
296 | GOOGLE_ID=Your ID
297 | GOOGLE_SECRET=Your Secret
298 | GOOGLE_URL=https://example.com/auth/google/callback
299 |
300 | VKONTAKTE_KEY=Your ID
301 | VKONTAKTE_SECRET=Your Secret
302 | VKONTAKTE_REDIRECT_URI=https://example.com/auth/vkontakte/callback
303 |
304 | ```
305 |
306 | #### VerifyCsrfToken Middleware
307 |
308 | you may need to disable Csrf for the route if you receive `Error: Request failed with status code 419`
309 |
310 | ```php
311 |
312 |
86 | * @copyright Method taken from https://github.com/sahat/satellizer
87 | *
88 | * @param {String} baseUrl Base url
89 | * @param {String} url URI
90 | * @return {String}
91 | */
92 | function joinUrl(baseUrl, url) {
93 | if (/^(?:[a-z]+:)?\/\//i.test(url)) {
94 | return url;
95 | }
96 | var joined = [baseUrl, url].join('/');
97 | var normalize = function (str) {
98 | return str
99 | .replace(/[\/]+/g, '/')
100 | .replace(/\/\?/g, '?')
101 | .replace(/\/\#/g, '#')
102 | .replace(/\:\//g, '://');
103 | };
104 | return normalize(joined);
105 | }
106 |
107 | /**
108 | * Get full path based on current location
109 | *
110 | * @author Sahat Yalkabov
111 | * @copyright Method taken from https://github.com/sahat/satellizer
112 | *
113 | * @param {Location} location
114 | * @return {String}
115 | */
116 | function getFullUrlPath(location) {
117 | var isHttps = location.protocol === 'https:';
118 | return location.protocol + '//' + location.hostname +
119 | ':' + (location.port || (isHttps ? '443' : '80')) +
120 | (/^\//.test(location.pathname) ? location.pathname : '/' + location.pathname);
121 | }
122 |
123 | /**
124 | * Parse query string variables
125 | *
126 | * @author Sahat Yalkabov
127 | * @copyright Method taken from https://github.com/sahat/satellizer
128 | *
129 | * @param {String} Query string
130 | * @return {String}
131 | */
132 | function parseQueryString(str) {
133 | var obj = {};
134 | var key;
135 | var value;
136 | (str || '').split('&').forEach(function (keyValue) {
137 | if (keyValue) {
138 | value = keyValue.split('=');
139 | key = decodeURIComponent(value[0]);
140 | obj[key] = (!!value[1]) ? decodeURIComponent(value[1]) : true;
141 | }
142 | });
143 | return obj;
144 | }
145 |
146 | /**
147 | * Decode base64 string
148 | * @author Sahat Yalkabov
149 | * @copyright Method taken from https://github.com/sahat/satellizer
150 | *
151 | * @param {String} str base64 encoded string
152 | * @return {Object}
153 | */
154 |
155 |
156 | function parseCookies(str) {
157 | if (str.length === 0) { return {}; }
158 | var parsed = {};
159 | var pattern = new RegExp('\\s*;\\s*');
160 | str.split(pattern).forEach(function (i) {
161 | var ref = i.split('=');
162 | var encodedKey = ref[0];
163 | var encodedValue = ref[1];
164 | var key = decodeURIComponent(encodedKey);
165 | var value = decodeURIComponent(encodedValue);
166 | parsed[key] = value;
167 | });
168 | return parsed;
169 | }
170 |
171 | function formatOptions(options) {
172 | var path = options.path;
173 | var domain = options.domain;
174 | var expires = options.expires;
175 | var secure = options.secure;
176 | return [
177 | typeof path === 'undefined' || path === null
178 | ? '' : ';path=' + path,
179 | typeof domain === 'undefined' || domain === null
180 | ? '' : ';domain=' + domain,
181 | typeof expires === 'undefined' || expires === null
182 | ? '' : ';expires=' + expires.toUTCString(),
183 | typeof secure === 'undefined' || secure === null || secure === false
184 | ? '' : ';secure'
185 | ].join('');
186 | }
187 |
188 | function formatCookie(key, value, options) {
189 | return [
190 | encodeURIComponent(key),
191 | '=',
192 | encodeURIComponent(value),
193 | formatOptions(options)
194 | ].join('');
195 | }
196 |
197 | // Store setTimeout reference so promise-polyfill will be unaffected by
198 | // other code modifying setTimeout (like sinon.useFakeTimers())
199 | var setTimeoutFunc = setTimeout;
200 |
201 | function noop() {}
202 |
203 | // Polyfill for Function.prototype.bind
204 | function bind(fn, thisArg) {
205 | return function () {
206 | fn.apply(thisArg, arguments);
207 | };
208 | }
209 |
210 | function Promise$1(fn) {
211 | if (typeof this !== 'object') { throw new TypeError('Promises must be constructed via new'); }
212 | if (typeof fn !== 'function') { throw new TypeError('not a function'); }
213 | this._state = 0;
214 | this._handled = false;
215 | this._value = undefined;
216 | this._deferreds = [];
217 |
218 | doResolve(fn, this);
219 | }
220 |
221 | function handle(self, deferred) {
222 | while (self._state === 3) {
223 | self = self._value;
224 | }
225 | if (self._state === 0) {
226 | self._deferreds.push(deferred);
227 | return;
228 | }
229 | self._handled = true;
230 | Promise$1._immediateFn(function () {
231 | var cb = self._state === 1 ? deferred.onFulfilled : deferred.onRejected;
232 | if (cb === null) {
233 | (self._state === 1 ? resolve : reject)(deferred.promise, self._value);
234 | return;
235 | }
236 | var ret;
237 | try {
238 | ret = cb(self._value);
239 | } catch (e) {
240 | reject(deferred.promise, e);
241 | return;
242 | }
243 | resolve(deferred.promise, ret);
244 | });
245 | }
246 |
247 | function resolve(self, newValue) {
248 | try {
249 | // Promise Resolution Procedure: https://github.com/promises-aplus/promises-spec#the-promise-resolution-procedure
250 | if (newValue === self) { throw new TypeError('A promise cannot be resolved with itself.'); }
251 | if (newValue && (typeof newValue === 'object' || typeof newValue === 'function')) {
252 | var then = newValue.then;
253 | if (newValue instanceof Promise$1) {
254 | self._state = 3;
255 | self._value = newValue;
256 | finale(self);
257 | return;
258 | } else if (typeof then === 'function') {
259 | doResolve(bind(then, newValue), self);
260 | return;
261 | }
262 | }
263 | self._state = 1;
264 | self._value = newValue;
265 | finale(self);
266 | } catch (e) {
267 | reject(self, e);
268 | }
269 | }
270 |
271 | function reject(self, newValue) {
272 | self._state = 2;
273 | self._value = newValue;
274 | finale(self);
275 | }
276 |
277 | function finale(self) {
278 | if (self._state === 2 && self._deferreds.length === 0) {
279 | Promise$1._immediateFn(function() {
280 | if (!self._handled) {
281 | Promise$1._unhandledRejectionFn(self._value);
282 | }
283 | });
284 | }
285 |
286 | for (var i = 0, len = self._deferreds.length; i < len; i++) {
287 | handle(self, self._deferreds[i]);
288 | }
289 | self._deferreds = null;
290 | }
291 |
292 | function Handler(onFulfilled, onRejected, promise) {
293 | this.onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : null;
294 | this.onRejected = typeof onRejected === 'function' ? onRejected : null;
295 | this.promise = promise;
296 | }
297 |
298 | /**
299 | * Take a potentially misbehaving resolver function and make sure
300 | * onFulfilled and onRejected are only called once.
301 | *
302 | * Makes no guarantees about asynchrony.
303 | */
304 | function doResolve(fn, self) {
305 | var done = false;
306 | try {
307 | fn(function (value) {
308 | if (done) { return; }
309 | done = true;
310 | resolve(self, value);
311 | }, function (reason) {
312 | if (done) { return; }
313 | done = true;
314 | reject(self, reason);
315 | });
316 | } catch (ex) {
317 | if (done) { return; }
318 | done = true;
319 | reject(self, ex);
320 | }
321 | }
322 |
323 | Promise$1.prototype['catch'] = function (onRejected) {
324 | return this.then(null, onRejected);
325 | };
326 |
327 | Promise$1.prototype.then = function (onFulfilled, onRejected) {
328 | var prom = new (this.constructor)(noop);
329 |
330 | handle(this, new Handler(onFulfilled, onRejected, prom));
331 | return prom;
332 | };
333 |
334 | Promise$1.all = function (arr) {
335 | var args = Array.prototype.slice.call(arr);
336 |
337 | return new Promise$1(function (resolve, reject) {
338 | if (args.length === 0) { return resolve([]); }
339 | var remaining = args.length;
340 |
341 | function res(i, val) {
342 | try {
343 | if (val && (typeof val === 'object' || typeof val === 'function')) {
344 | var then = val.then;
345 | if (typeof then === 'function') {
346 | then.call(val, function (val) {
347 | res(i, val);
348 | }, reject);
349 | return;
350 | }
351 | }
352 | args[i] = val;
353 | if (--remaining === 0) {
354 | resolve(args);
355 | }
356 | } catch (ex) {
357 | reject(ex);
358 | }
359 | }
360 |
361 | for (var i = 0; i < args.length; i++) {
362 | res(i, args[i]);
363 | }
364 | });
365 | };
366 |
367 | Promise$1.resolve = function (value) {
368 | if (value && typeof value === 'object' && value.constructor === Promise$1) {
369 | return value;
370 | }
371 |
372 | return new Promise$1(function (resolve) {
373 | resolve(value);
374 | });
375 | };
376 |
377 | Promise$1.reject = function (value) {
378 | return new Promise$1(function (resolve, reject) {
379 | reject(value);
380 | });
381 | };
382 |
383 | Promise$1.race = function (values) {
384 | return new Promise$1(function (resolve, reject) {
385 | for (var i = 0, len = values.length; i < len; i++) {
386 | values[i].then(resolve, reject);
387 | }
388 | });
389 | };
390 |
391 | // Use polyfill for setImmediate for performance gains
392 | Promise$1._immediateFn = (typeof setImmediate === 'function' && function (fn) { setImmediate(fn); }) ||
393 | function (fn) {
394 | setTimeoutFunc(fn, 0);
395 | };
396 |
397 | Promise$1._unhandledRejectionFn = function _unhandledRejectionFn(err) {
398 | if (typeof console !== 'undefined' && console) {
399 | console.warn('Possible Unhandled Promise Rejection:', err); // eslint-disable-line no-console
400 | }
401 | };
402 |
403 | /**
404 | * Set the immediate function to execute callbacks
405 | * @param fn {function} Function to execute
406 | * @deprecated
407 | */
408 | Promise$1._setImmediateFn = function _setImmediateFn(fn) {
409 | Promise$1._immediateFn = fn;
410 | };
411 |
412 | /**
413 | * Change the function to execute on unhandled rejection
414 | * @param {function} fn Function to execute on unhandled rejection
415 | * @deprecated
416 | */
417 | Promise$1._setUnhandledRejectionFn = function _setUnhandledRejectionFn(fn) {
418 | Promise$1._unhandledRejectionFn = fn;
419 | };
420 |
421 | /**
422 | * Default configuration
423 | */
424 | var defaultOptions = {
425 | baseUrl: null,
426 | tokenName: 'token',
427 | tokenPrefix: 'vueauth',
428 | tokenHeader: 'Authorization',
429 | tokenType: 'Bearer',
430 | loginUrl: '/auth/login',
431 | registerUrl: '/auth/register',
432 | logoutUrl: null,
433 | storageType: 'localStorage',
434 | storageNamespace: 'vue-social-auth',
435 | cookieStorage: {
436 | domain: window.location.hostname,
437 | path: '/',
438 | secure: false
439 | },
440 | requestDataKey: 'data',
441 | responseDataKey: 'data',
442 |
443 | /**
444 | * Default request interceptor for Axios library
445 | * @context {VueSocialauth}
446 | */
447 | bindRequestInterceptor: function ($auth) {
448 |
449 | var tokenHeader = $auth.options.tokenHeader;
450 |
451 | $auth.$http.interceptors.request.use(function (config) {
452 | delete config.headers[tokenHeader];
453 | return config
454 | });
455 |
456 |
457 | },
458 |
459 | /**
460 | * Default response interceptor for Axios library
461 | * @contect {VueSocialauth}
462 | */
463 | bindResponseInterceptor: function ($auth) {
464 | $auth.$http.interceptors.response.use(function (response) {
465 | return response
466 | });
467 | },
468 |
469 | providers: {
470 | facebook: {
471 | name: 'facebook',
472 | url: '/auth/facebook',
473 | authorizationEndpoint: 'https://www.facebook.com/v2.5/dialog/oauth',
474 | redirectUri: window.location.origin + '/',
475 | requiredUrlParams: ['display', 'scope'],
476 | scope: ['email'],
477 | scopeDelimiter: ',',
478 | display: 'popup',
479 | oauthType: '2.0',
480 | popupOptions: { width: 580, height: 400 }
481 | },
482 |
483 | google: {
484 | name: 'google',
485 | url: '/auth/google',
486 | authorizationEndpoint: 'https://accounts.google.com/o/oauth2/auth',
487 | redirectUri: window.location.origin,
488 | requiredUrlParams: ['scope'],
489 | optionalUrlParams: ['display'],
490 | scope: ['profile', 'email'],
491 | scopePrefix: 'openid',
492 | scopeDelimiter: ' ',
493 | display: 'popup',
494 | oauthType: '2.0',
495 | popupOptions: { width: 452, height: 633 }
496 | },
497 |
498 | github: {
499 | name: 'github',
500 | url: '/auth/github',
501 | authorizationEndpoint: 'https://github.com/login/oauth/authorize',
502 | redirectUri: window.location.origin,
503 | optionalUrlParams: ['scope'],
504 | scope: ['user:email'],
505 | scopeDelimiter: ' ',
506 | oauthType: '2.0',
507 | popupOptions: { width: 1020, height: 618 }
508 | },
509 |
510 | instagram: {
511 | name: 'instagram',
512 | url: '/auth/instagram',
513 | authorizationEndpoint: 'https://api.instagram.com/oauth/authorize',
514 | redirectUri: window.location.origin,
515 | requiredUrlParams: ['scope'],
516 | scope: ['basic'],
517 | scopeDelimiter: '+',
518 | oauthType: '2.0',
519 | popupOptions: { width: null, height: null }
520 | },
521 |
522 | twitter: {
523 | name: 'twitter',
524 | url: '/auth/twitter',
525 | authorizationEndpoint: 'https://api.twitter.com/oauth/authenticate',
526 | redirectUri: window.location.origin,
527 | oauthType: '1.0',
528 | popupOptions: { width: 495, height: 645 }
529 | },
530 |
531 | bitbucket: {
532 | name: 'bitbucket',
533 | url: '/auth/bitbucket',
534 | authorizationEndpoint: 'https://bitbucket.org/site/oauth2/authorize',
535 | redirectUri: window.location.origin + '/',
536 | optionalUrlParams: ['scope'],
537 | scope: ['email'],
538 | scopeDelimiter: ' ',
539 | oauthType: '2.0',
540 | popupOptions: { width: 1020, height: 618 }
541 | },
542 |
543 | linkedin: {
544 | name: 'linkedin',
545 | url: '/auth/linkedin',
546 | authorizationEndpoint: 'https://www.linkedin.com/oauth/v2/authorization',
547 | redirectUri: window.location.origin,
548 | requiredUrlParams: ['state','scope'],
549 | scope: ['r_liteprofile','r_emailaddress'],
550 | scopeDelimiter: ' ',
551 | state: 'STATE',
552 | oauthType: '2.0',
553 | popupOptions: { width: 527, height: 582 }
554 | },
555 |
556 | vkontakte: {
557 | name: 'vkontakte',
558 | url: '/auth/vkontakte',
559 | authorizationEndpoint: 'https://oauth.vk.com/authorize',
560 | redirectUri: window.location.origin + '/',
561 | requiredUrlParams: ['scope'],
562 | scope: ['email'],
563 | scopeDelimiter: ',',
564 | display: 'popup',
565 | oauthType: '2.0',
566 | popupOptions: { width: 580, height: 400 }
567 | },
568 |
569 | live: {
570 | name: 'live',
571 | url: '/auth/live',
572 | authorizationEndpoint: 'https://login.live.com/oauth20_authorize.srf',
573 | redirectUri: window.location.origin,
574 | requiredUrlParams: ['display', 'scope'],
575 | scope: ['wl.emails'],
576 | scopeDelimiter: ' ',
577 | display: 'popup',
578 | oauthType: '2.0',
579 | popupOptions: { width: 500, height: 560 }
580 | },
581 |
582 | oauth1: {
583 | name: null,
584 | url: '/auth/oauth1',
585 | authorizationEndpoint: null,
586 | redirectUri: window.location.origin,
587 | oauthType: '1.0',
588 | popupOptions: null
589 | },
590 |
591 | oauth2: {
592 | name: null,
593 | url: '/auth/oauth2',
594 | clientId: null,
595 | redirectUri: window.location.origin,
596 | authorizationEndpoint: null,
597 | defaultUrlParams: ['response_type', 'client_id', 'redirect_uri'],
598 | requiredUrlParams: null,
599 | optionalUrlParams: null,
600 | scope: null,
601 | scopePrefix: null,
602 | scopeDelimiter: null,
603 | state: null,
604 | oauthType: '2.0',
605 | popupOptions: null,
606 | responseType: 'code',
607 | responseParams: {
608 | code: 'code',
609 | clientId: 'clientId',
610 | redirectUri: 'redirectUri'
611 | }
612 | }
613 | }
614 | };
615 |
616 | var CookieStorage = function CookieStorage(defaultOptions) {
617 | this._defaultOptions = objectExtend({
618 | domain: window.location.hostname,
619 | expires: null,
620 | path: '/',
621 | secure: false
622 | }, defaultOptions);
623 | };
624 |
625 | CookieStorage.prototype.setItem = function setItem (key, value) {
626 | var options = objectExtend({}, this._defaultOptions);
627 | var cookie = formatCookie(key, value, options);
628 | this._setCookie(cookie);
629 | };
630 |
631 | CookieStorage.prototype.getItem = function getItem (key) {
632 | var cookies = parseCookies(this._getCookie());
633 | return cookies.hasOwnProperty(key) ? cookies[key] : null;
634 | };
635 |
636 | CookieStorage.prototype.removeItem = function removeItem (key) {
637 | var value = '';
638 | var defaultOptions = objectExtend({}, this._defaultOptions);
639 | var options = objectExtend(defaultOptions, {
640 | expires: new Date(0)
641 | });
642 | var cookie = formatCookie(key, value, options);
643 | this._setCookie(cookie);
644 | };
645 |
646 | CookieStorage.prototype._getCookie = function _getCookie () {
647 | return typeof document === 'undefined'
648 | ? '' : typeof document.cookie === 'undefined'
649 | ? '' : document.cookie;
650 | };
651 |
652 | CookieStorage.prototype._setCookie = function _setCookie (cookie) {
653 | document.cookie = cookie;
654 | };
655 |
656 | var LocalStorage = function LocalStorage(namespace) {
657 | this.namespace = namespace || null;
658 | };
659 |
660 | LocalStorage.prototype.setItem = function setItem (key, value) {
661 | window.localStorage.setItem(this._getStorageKey(key), value);
662 | };
663 |
664 | LocalStorage.prototype.getItem = function getItem (key) {
665 | return window.localStorage.getItem(this._getStorageKey(key))
666 | };
667 |
668 | LocalStorage.prototype.removeItem = function removeItem (key) {
669 | window.localStorage.removeItem(this._getStorageKey(key));
670 | };
671 |
672 | LocalStorage.prototype._getStorageKey = function _getStorageKey (key) {
673 | if (this.namespace) {
674 | return [this.namespace, key].join('.')
675 | }
676 | return key;
677 | };
678 |
679 | var MemoryStorage = function MemoryStorage(namespace) {
680 | this.namespace = namespace || null;
681 | this._storage = {};
682 | };
683 |
684 | MemoryStorage.prototype.setItem = function setItem (key, value) {
685 | this._storage[this._getStorageKey(key)] = value;
686 | };
687 |
688 | MemoryStorage.prototype.getItem = function getItem (key) {
689 | return this._storage[this._getStorageKey(key)]
690 | };
691 |
692 | MemoryStorage.prototype.removeItem = function removeItem (key) {
693 | delete this._storage[this._getStorageKey(key)];
694 | };
695 |
696 | MemoryStorage.prototype._getStorageKey = function _getStorageKey (key) {
697 | if (this.namespace) {
698 | return [this.namespace, key].join('.')
699 | }
700 | return key;
701 | };
702 |
703 | var LocalStorage$2 = function LocalStorage(namespace) {
704 | this.namespace = namespace || null;
705 | };
706 |
707 | LocalStorage$2.prototype.setItem = function setItem (key, value) {
708 | window.sessionStorage.setItem(this._getStorageKey(key), value);
709 | };
710 |
711 | LocalStorage$2.prototype.getItem = function getItem (key) {
712 | return window.sessionStorage.getItem(this._getStorageKey(key))
713 | };
714 |
715 | LocalStorage$2.prototype.removeItem = function removeItem (key) {
716 | window.sessionStorage.removeItem(this._getStorageKey(key));
717 | };
718 |
719 | LocalStorage$2.prototype._getStorageKey = function _getStorageKey (key) {
720 | if (this.namespace) {
721 | return [this.namespace, key].join('.')
722 | }
723 | return key;
724 | };
725 |
726 | function StorageFactory(options) {
727 | switch (options.storageType) {
728 | case 'localStorage':
729 | try {
730 | window.localStorage.setItem('testKey', 'test');
731 | window.localStorage.removeItem('testKey');
732 | return new LocalStorage(options.storageNamespace)
733 | } catch(e) {}
734 |
735 | case 'sessionStorage':
736 | try {
737 | window.sessionStorage.setItem('testKey', 'test');
738 | window.sessionStorage.removeItem('testKey');
739 | return new LocalStorage$2(options.storageNamespace)
740 | } catch (e) {}
741 |
742 | case 'cookieStorage':
743 | return new CookieStorage(options.cookieStorage);
744 |
745 | case 'memoryStorage':
746 | default:
747 | return new MemoryStorage(options.storageNamespace)
748 | break;
749 | }
750 | }
751 |
752 | /**
753 | * OAuth2 popup management class
754 | *
755 | * @author Sahat Yalkabov
756 | * @copyright Class mostly taken from https://github.com/sahat/satellizer
757 | * and adjusted to fit vue-social-auth library
758 | */
759 | var OAuthPopup = function OAuthPopup(url, name, popupOptions) {
760 | this.popup = null;
761 | this.url = url;
762 | this.name = name;
763 | this.popupOptions = popupOptions;
764 | };
765 |
766 | OAuthPopup.prototype.open = function open (redirectUri, skipPooling) {
767 | try {
768 | this.popup = window.open(this.url, this.name, this._stringifyOptions());
769 | if (this.popup && this.popup.focus) {
770 | this.popup.focus();
771 | }
772 |
773 | if (skipPooling) {
774 | return Promise$1.resolve()
775 | } else {
776 | return this.pooling(redirectUri)
777 | }
778 | } catch(e) {
779 | return Promise$1.reject(new Error('OAuth popup error occurred'))
780 | }
781 | };
782 |
783 | OAuthPopup.prototype.pooling = function pooling (redirectUri) {
784 | var this$1 = this;
785 |
786 | return new Promise$1(function (resolve, reject) {
787 | var redirectUriParser = document.createElement('a');
788 | redirectUriParser.href = redirectUri;
789 | var redirectUriPath = getFullUrlPath(redirectUriParser);
790 |
791 | var poolingInterval = setInterval(function () {
792 | if (!this$1.popup || this$1.popup.closed || this$1.popup.closed === undefined) {
793 | clearInterval(poolingInterval);
794 | poolingInterval = null;
795 | reject(new Error('Auth popup window closed'));
796 | }
797 |
798 | try {
799 | var popupWindowPath = getFullUrlPath(this$1.popup.location);
800 |
801 | if (popupWindowPath === redirectUriPath) {
802 | if (this$1.popup.location.search || this$1.popup.location.hash) {
803 | var query = parseQueryString(this$1.popup.location.search.substring(1).replace(/\/$/, ''));
804 | var hash = parseQueryString(this$1.popup.location.hash.substring(1).replace(/[\/$]/, ''));
805 | var params = objectExtend({}, query);
806 | params = objectExtend(params, hash);
807 |
808 | if (params.error) {
809 | reject(new Error(params.error));
810 | } else {
811 | resolve(params);
812 | }
813 | } else {
814 | reject(new Error('OAuth redirect has occurred but no query or hash parameters were found.'));
815 | }
816 |
817 | clearInterval(poolingInterval);
818 | poolingInterval = null;
819 | this$1.popup.close();
820 | }
821 | } catch(e) {
822 | // Ignore DOMException: Blocked a frame with origin from accessing a cross-origin frame.
823 | }
824 | }, 250);
825 | })
826 | };
827 |
828 | OAuthPopup.prototype._stringifyOptions = function _stringifyOptions () {
829 | var this$1 = this;
830 |
831 | var options = [];
832 | for (var optionKey in this$1.popupOptions) {
833 | if (!isUndefined(this$1.popupOptions[optionKey])) {
834 | options.push((optionKey + "=" + (this$1.popupOptions[optionKey])));
835 | }
836 | }
837 | return options.join(',')
838 | };
839 |
840 | var defaultProviderConfig = {
841 | name: null,
842 | url: null,
843 | authorizationEndpoint: null,
844 | scope: null,
845 | scopePrefix: null,
846 | scopeDelimiter: null,
847 | redirectUri: null,
848 | requiredUrlParams: null,
849 | defaultUrlParams: null,
850 | oauthType: '1.0',
851 | popupOptions: {}
852 | };
853 |
854 | var OAuth = function OAuth($http, storage, providerConfig, options) {
855 | this.$http = $http;
856 | this.storage = storage;
857 | this.providerConfig = objectExtend({}, defaultProviderConfig);
858 | this.providerConfig = objectExtend(this.providerConfig, providerConfig);
859 | this.options = options;
860 | };
861 |
862 | /**
863 | * Initialize OAuth1 process
864 | * @param{Object} userData User data
865 | * @return {Promise}
866 | */
867 | OAuth.prototype.init = function init (userData) {
868 | var this$1 = this;
869 |
870 | this.oauthPopup = new OAuthPopup('about:blank', this.providerConfig.name, this.providerConfig.popupOptions);
871 |
872 | if (window && !window['cordova']) {
873 | this.oauthPopup.open(this.providerConfig.redirectUri, true);
874 | }
875 |
876 | return this.getRequestToken().then(function (response) {
877 | return this$1.openPopup(response).then(function (popupResponse) {
878 | return this$1.exchangeForToken(popupResponse, userData)
879 | })
880 | })
881 | };
882 |
883 | /**
884 | * Get OAuth1 request token
885 | * @return {Promise}
886 | */
887 | OAuth.prototype.getRequestToken = function getRequestToken () {
888 | var requestOptions = {};
889 | requestOptions.method = 'POST';
890 | requestOptions[this.options.requestDataKey] = objectExtend({}, this.providerConfig);
891 | requestOptions.withCredentials = this.options.withCredentials;
892 | if (this.options.baseUrl) {
893 | requestOptions.url = joinUrl(this.options.baseUrl, this.providerConfig.url);
894 | } else {
895 | requestOptions.url = this.providerConfig.url;
896 | }
897 |
898 | return this.$http(requestOptions)
899 | };
900 |
901 | /**
902 | * Open OAuth1 popup
903 | * @param{Object} response Response object containing request token
904 | * @return {Promise}
905 | */
906 | OAuth.prototype.openPopup = function openPopup (response) {
907 | var url = [this.providerConfig.authorizationEndpoint, this.buildQueryString(response[this.options.responseDataKey])].join('?');
908 |
909 | this.oauthPopup.popup.location = url;
910 | if (window && window['cordova']) {
911 | return this.oauthPopup.open(this.providerConfig.redirectUri)
912 | } else {
913 | return this.oauthPopup.pooling(this.providerConfig.redirectUri)
914 | }
915 | };
916 |
917 | /**
918 | * Exchange token and token verifier for access token
919 | * @param{Object} oauth OAuth data containing token and token verifier
920 | * @param{Object} userData User data
921 | * @return {Promise}
922 | */
923 | OAuth.prototype.exchangeForToken = function exchangeForToken (oauth, userData) {
924 | var payload = objectExtend({}, userData);
925 | payload = objectExtend(payload, oauth);
926 | var requestOptions = {};
927 | requestOptions.method = 'POST';
928 | requestOptions[this.options.requestDataKey] = payload;
929 | requestOptions.withCredentials = this.options.withCredentials;
930 | if (this.options.baseUrl) {
931 | requestOptions.url = joinUrl(this.options.baseUrl, this.providerConfig.url);
932 | } else {
933 | requestOptions.url = this.providerConfig.url;
934 | }
935 | return this.$http(requestOptions)
936 | };
937 |
938 | OAuth.prototype.buildQueryString = function buildQueryString (params) {
939 | var parsedParams = [];
940 | for (var key in params) {
941 | var value = params[key];
942 | parsedParams.push(encodeURIComponent(key) + '=' + encodeURIComponent(value));
943 | }
944 | return parsedParams.join('&');
945 | };
946 |
947 | /**
948 | * Default provider configuration
949 | * @type {Object}
950 | */
951 | var defaultProviderConfig$1 = {
952 | name: null,
953 | url: null,
954 | clientId: null,
955 | authorizationEndpoint: null,
956 | redirectUri: null,
957 | scope: null,
958 | scopePrefix: null,
959 | scopeDelimiter: null,
960 | state: null,
961 | requiredUrlParams: null,
962 | defaultUrlParams: ['response_type', 'client_id', 'redirect_uri'],
963 | responseType: 'code',
964 | responseParams: {
965 | code: 'code',
966 | clientId: 'clientId',
967 | redirectUri: 'redirectUri'
968 | },
969 | oauthType: '2.0',
970 | popupOptions: {}
971 | };
972 |
973 | var OAuth2 = function OAuth2($http, storage, providerConfig, options) {
974 | this.$http = $http;
975 | this.storage = storage;
976 | this.providerConfig = objectExtend({}, defaultProviderConfig$1);
977 | this.providerConfig = objectExtend(this.providerConfig, providerConfig);
978 | this.options = options;
979 | };
980 |
981 | OAuth2.prototype.init = function init (userData) {
982 | var this$1 = this;
983 |
984 | var stateName = this.providerConfig.name + '_state';
985 | if (isFunction(this.providerConfig.state)) {
986 | this.storage.setItem(stateName, this.providerConfig.state());
987 | } else if (isString(this.providerConfig.state)) {
988 | this.storage.setItem(stateName, this.providerConfig.state);
989 | }
990 |
991 | var url = [this.providerConfig.authorizationEndpoint, this._stringifyRequestParams()].join('?');
992 |
993 | this.oauthPopup = new OAuthPopup(url, this.providerConfig.name, this.providerConfig.popupOptions);
994 |
995 | return new Promise(function (resolve, reject) {
996 | this$1.oauthPopup.open(this$1.providerConfig.redirectUri).then(function (response) {
997 | if (this$1.providerConfig.responseType === 'code' || !this$1.providerConfig.url) {
998 | return resolve(response)
999 | }
1000 |
1001 | if (response.state && response.state !== this$1.storage.getItem(stateName)) {
1002 | return reject(new Error('State parameter value does not match original OAuth request state value'))
1003 | }
1004 |
1005 | resolve(this$1.exchangeForToken(response, userData));
1006 | }).catch(function (err) {
1007 | reject(err);
1008 | });
1009 | })
1010 | };
1011 |
1012 | /**
1013 | * Exchange temporary oauth data for access token
1014 | * @author Sahat Yalkabov
1015 | * @copyright Method taken from https://github.com/sahat/satellizer
1016 | *
1017 | * @param{[type]} oauth [description]
1018 | * @param{[type]} userData [description]
1019 | * @return {[type]} [description]
1020 | */
1021 | OAuth2.prototype.exchangeForToken = function exchangeForToken (oauth, userData) {
1022 | var this$1 = this;
1023 |
1024 | var payload = objectExtend({}, userData);
1025 |
1026 | for (var key in defaultProviderConfig$1.responseParams) {
1027 | var value = defaultProviderConfig$1[key];
1028 |
1029 | switch(key) {
1030 | case 'code':
1031 | payload[key] = oauth.code;
1032 | break
1033 | case 'clientId':
1034 | payload[key] = this$1.providerConfig.clientId;
1035 | break
1036 | case 'redirectUri':
1037 | payload[key] = this$1.providerConfig.redirectUri;
1038 | break
1039 | default:
1040 | payload[key] = oauth[key];
1041 | }
1042 | }
1043 |
1044 | if (oauth.state) {
1045 | payload.state = oauth.state;
1046 | }
1047 |
1048 | var exchangeTokenUrl;
1049 | if (this.options.baseUrl) {
1050 | exchangeTokenUrl = joinUrl(this.options.baseUrl, this.providerConfig.url);
1051 | } else {
1052 | exchangeTokenUrl = this.providerConfig.url;
1053 | }
1054 |
1055 | return this.$http.post(exchangeTokenUrl, payload, {
1056 | withCredentials: this.options.withCredentials
1057 | })
1058 | };
1059 |
1060 | /**
1061 | * Stringify oauth params
1062 | * @author Sahat Yalkabov
1063 | * @copyright Method taken from https://github.com/sahat/satellizer
1064 | *
1065 | * @return {String}
1066 | */
1067 | OAuth2.prototype._stringifyRequestParams = function _stringifyRequestParams () {
1068 | var this$1 = this;
1069 |
1070 | var keyValuePairs = [];
1071 | var paramCategories = ['defaultUrlParams', 'requiredUrlParams', 'optionalUrlParams'];
1072 |
1073 | paramCategories.forEach(function (categoryName) {
1074 | if (!this$1.providerConfig[categoryName]) { return }
1075 | if (!Array.isArray(this$1.providerConfig[categoryName])) { return }
1076 |
1077 | this$1.providerConfig[categoryName].forEach(function (paramName) {
1078 | var camelCaseParamName = camelCase(paramName);
1079 | var paramValue = isFunction(this$1.providerConfig[paramName]) ? this$1.providerConfig[paramName]() : this$1.providerConfig[camelCaseParamName];
1080 |
1081 | if (paramName === 'redirect_uri' && !paramValue) { return }
1082 |
1083 | if (paramName === 'state') {
1084 | var stateName = this$1.providerConfig.name + '_state';
1085 | paramValue = encodeURIComponent(this$1.storage.getItem(stateName));
1086 | }
1087 | if (paramName === 'scope' && Array.isArray(paramValue)) {
1088 | paramValue = paramValue.join(this$1.providerConfig.scopeDelimiter);
1089 | if (this$1.providerConfig.scopePrefix) {
1090 | paramValue = [this$1.providerConfig.scopePrefix, paramValue].join(this$1.providerConfig.scopeDelimiter);
1091 | }
1092 | }
1093 |
1094 | keyValuePairs.push([paramName, paramValue]);
1095 | });
1096 | });
1097 |
1098 | return keyValuePairs.map(function (param) {
1099 | return param.join('=')
1100 | }).join('&')
1101 | };
1102 |
1103 | var VueSocialauth = function VueSocialauth($http, overrideOptions) {
1104 | var options = objectExtend({}, defaultOptions);
1105 | options = objectExtend(options, overrideOptions);
1106 | var storage = StorageFactory(options);
1107 |
1108 | Object.defineProperties(this, {
1109 | $http: {
1110 | get: function get() {
1111 | return $http
1112 | }
1113 | },
1114 |
1115 | options: {
1116 | get: function get() {
1117 | return options
1118 | }
1119 | },
1120 |
1121 | storage: {
1122 | get: function get() {
1123 | return storage
1124 | }
1125 | },
1126 |
1127 | tokenName: {
1128 | get: function get() {
1129 | if (this.options.tokenPrefix) {
1130 | return [this.options.tokenPrefix, this.options.tokenName].join('_')
1131 | } else {
1132 | return this.options.tokenName
1133 | }
1134 | }
1135 | }
1136 | });
1137 |
1138 | // Setup request interceptors
1139 | if (this.options.bindRequestInterceptor && isFunction(this.options.bindRequestInterceptor) &&
1140 | this.options.bindResponseInterceptor && isFunction(this.options.bindResponseInterceptor)) {
1141 |
1142 | this.options.bindRequestInterceptor.call(this, this);
1143 | this.options.bindResponseInterceptor.call(this, this);
1144 | } else {
1145 | throw new Error('Both request and response interceptors must be functions')
1146 | }
1147 | };
1148 |
1149 | /**
1150 | * Check if user is authenticated
1151 | * @author Sahat Yalkabov
1152 | * @copyright Method taken from https://github.com/sahat/satellizer
1153 | * @return {Boolean}
1154 | */
1155 | // isAuthenticated() {
1156 | // let token = this.storage.getItem(this.tokenName)
1157 |
1158 | // if (token) {// Token is present
1159 | // if (token.split('.').length === 3) {// Token with a valid JWT format XXX.YYY.ZZZ
1160 | // try { // Could be a valid JWT or an access token with the same format
1161 | // const base64Url = token.split('.')[1];
1162 | // const base64 = base64Url.replace('-', '+').replace('_', '/');
1163 | // const exp = JSON.parse(window.atob(base64)).exp;
1164 | // if (typeof exp === 'number') {// JWT with an optonal expiration claims
1165 | // return Math.round(new Date().getTime() / 1000) < exp;
1166 | // }
1167 | // } catch (e) {
1168 | // return true;// Pass: Non-JWT token that looks like JWT
1169 | // }
1170 | // }
1171 | // return true;// Pass: All other tokens
1172 | // }
1173 | // return false
1174 | // }
1175 |
1176 | /**
1177 | * Get token if user is authenticated
1178 | * @return {String} Authentication token
1179 | */
1180 | VueSocialauth.prototype.getToken = function getToken () {
1181 | return this.storage.getItem(this.tokenName)
1182 | };
1183 |
1184 | /**
1185 | * Set new authentication token
1186 | * @param {String|Object} token
1187 | */
1188 | // setToken(response) {
1189 | // if (response[this.options.responseDataKey]) {
1190 | // response = response[this.options.responseDataKey];
1191 | // }
1192 |
1193 | // let token;
1194 | // if (response.access_token) {
1195 | // if (isObject(response.access_token) && isObject(response.access_token[this.options.responseDataKey])) {
1196 | // response = response.access_token
1197 | // } else if (isString(response.access_token)) {
1198 | // token = response.access_token
1199 | // }
1200 | // }
1201 |
1202 | // if (!token && response) {
1203 | // token = response[this.options.tokenName]
1204 | // }
1205 |
1206 | // if (token) {
1207 | // this.storage.setItem(this.tokenName, token)
1208 | // }
1209 | // }
1210 |
1211 | // getPayload() {
1212 | // const token = this.storage.getItem(this.tokenName);
1213 |
1214 | // if (token && token.split('.').length === 3) {
1215 | // try {
1216 | // const base64Url = token.split('.')[1];
1217 | // const base64 = base64Url.replace('-', '+').replace('_', '/');
1218 | // return JSON.parse(decodeBase64(base64));
1219 | // } catch (e) {}
1220 | // }
1221 | // }
1222 |
1223 | /**
1224 | * Login user using email and password
1225 | * @param{Object} user User data
1226 | * @param{Object} requestOptions Request options
1227 | * @return {Promise} Request promise
1228 | */
1229 | // login(user, requestOptions) {
1230 | // requestOptions = requestOptions || {}
1231 | // requestOptions.url = requestOptions.url ? requestOptions.url : joinUrl(this.options.baseUrl, this.options.loginUrl)
1232 | // requestOptions[this.options.requestDataKey] = user || requestOptions[this.options.requestDataKey]
1233 | // requestOptions.method = requestOptions.method || 'POST'
1234 | // requestOptions.withCredentials = requestOptions.withCredentials || this.options.withCredentials
1235 |
1236 | // return this.$http(requestOptions).then((response) => {
1237 | // this.setToken(response)
1238 | // return response
1239 | // })
1240 | // }
1241 |
1242 | /**
1243 | * Register new user
1244 | * @param{Object} user User data
1245 | * @param{Object} requestOptions Request options
1246 | * @return {Promise} Request promise
1247 | */
1248 | // register(user, requestOptions) {
1249 | // requestOptions = requestOptions || {}
1250 | // requestOptions.url = requestOptions.url ? requestOptions.url : joinUrl(this.options.baseUrl, this.options.registerUrl)
1251 | // requestOptions[this.options.requestDataKey] = user || requestOptions[this.options.requestDataKey]
1252 | // requestOptions.method = requestOptions.method || 'POST'
1253 | // requestOptions.withCredentials = requestOptions.withCredentials || this.options.withCredentials
1254 |
1255 | // return this.$http(requestOptions).then((response) => {
1256 | // this.setToken(response)
1257 | // return response
1258 | // })
1259 | // }
1260 |
1261 | /**
1262 | * Logout current user
1263 | * @param{Object} requestOptionsLogout request options object
1264 | * @return {Promise} Request promise
1265 | */
1266 | // logout(requestOptions) {
1267 | // if (!this.isAuthenticated()) {
1268 | // return Promise.reject(new Error('There is no currently authenticated user'))
1269 | // }
1270 |
1271 | // requestOptions = requestOptions || {}
1272 | // requestOptions.url = requestOptions.logoutUrl || this.options.logoutUrl
1273 |
1274 | // if (requestOptions.url) {
1275 | // requestOptions.method = requestOptions.method || 'POST'
1276 | // requestOptions.withCredentials = requestOptions.withCredentials || this.options.withCredentials
1277 |
1278 | // return this.$http(requestOptions).then((response) => {
1279 | // this.storage.removeItem(this.tokenName)
1280 | // })
1281 | // } else {
1282 | // this.storage.removeItem(this.tokenName)
1283 | // return Promise.resolve();
1284 | // }
1285 | // }
1286 |
1287 | /**
1288 | * Authenticate user using authentication provider
1289 | *
1290 | * @param{String} provider Provider name
1291 | * @param{Object} userData User data
1292 | * @param{Object} requestOptions Request options
1293 | * @return {Promise} Request promise
1294 | */
1295 | VueSocialauth.prototype.authenticate = function authenticate (provider, userData, requestOptions) {
1296 | var this$1 = this;
1297 |
1298 | return new Promise$1(function (resolve, reject) {
1299 | var providerConfig = this$1.options.providers[provider];
1300 | if (!providerConfig) {
1301 | return reject(new Error('Unknown provider'))
1302 | }
1303 |
1304 | var providerInstance;
1305 | switch (providerConfig.oauthType) {
1306 | case '1.0':
1307 | providerInstance = new OAuth(this$1.$http, this$1.storage, providerConfig, this$1.options);
1308 | break
1309 | case '2.0':
1310 | providerInstance = new OAuth2(this$1.$http, this$1.storage, providerConfig, this$1.options);
1311 | break
1312 | default:
1313 | return reject(new Error('Invalid OAuth type'))
1314 | break
1315 | }
1316 |
1317 | return providerInstance.init(userData).then(function (response) {
1318 | return resolve(response)
1319 |
1320 | }).catch(function (err) { return reject(err); })
1321 | })
1322 | };
1323 |
1324 | /**
1325 | * VueSocialauth plugin
1326 | * @param {Object} Vue
1327 | * @param {Object} options
1328 | */
1329 | function plugin(Vue, options) {
1330 | if (plugin.installed) {
1331 | return
1332 | }
1333 | plugin.installed = true;
1334 |
1335 | var property = options.property || '$auth';
1336 |
1337 | var vueAuthInstance = null;
1338 | Object.defineProperties(Vue.prototype, ( obj = {}, obj[property] = {
1339 | get: function get() {
1340 | if (!vueAuthInstance) {
1341 | // Request handler library not found, throw error
1342 | // verified vue or nuxt instance
1343 | if (this.$axios) {
1344 | vueAuthInstance = new VueSocialauth(this.$axios, options);
1345 | } else if (this.$http) {
1346 | vueAuthInstance = new VueSocialauth(this.$http, options);
1347 | } else {
1348 | throw new Error('Request handler instance not found')
1349 | }
1350 | }
1351 | return vueAuthInstance
1352 | }
1353 | }, obj ));
1354 | var obj;
1355 | }
1356 |
1357 | /**
1358 | * External factory helper for ES5 and CommonJS
1359 | * @param {Object} $http Instance of request handling library
1360 | * @param {Object} options Configuration object
1361 | * @return {VueSocialauth} VueSocialauth instance
1362 | */
1363 | plugin.factory = function ($http, options) {
1364 | return new VueSocialauth($http, options)
1365 | };
1366 |
1367 | module.exports = plugin;
1368 |
--------------------------------------------------------------------------------
/dist/vue-social-auth.es2017.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * vue-social-auth v0.0.1
3 | * https://github.com/diadal/vue-social-auth
4 | * Released under the MIT License.
5 | */
6 |
7 | if (typeof Object.assign != 'function') {
8 | Object.assign = function(target, varArgs) {
9 | 'use strict';
10 | var arguments$1 = arguments;
11 |
12 | if (target == null) {
13 | throw new TypeError('Cannot convert undefined or null to object');
14 | }
15 |
16 | var to = Object(target);
17 |
18 | for (var index = 1; index < arguments.length; index++) {
19 | var nextSource = arguments$1[index];
20 |
21 | if (nextSource != null) { // Skip over if undefined or null
22 | for (var nextKey in nextSource) {
23 | // Avoid bugs when hasOwnProperty is shadowed
24 | if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) {
25 | to[nextKey] = nextSource[nextKey];
26 | }
27 | }
28 | }
29 | }
30 | return to;
31 | };
32 | }
33 |
34 | function camelCase(name) {
35 | return name.replace(/([\:\-\_]+(.))/g, function (_, separator, letter, offset) {
36 | return offset ? letter.toUpperCase() : letter;
37 | });
38 | }
39 |
40 | function isUndefined(value) {
41 | return typeof value === 'undefined'
42 | }
43 |
44 |
45 |
46 |
47 |
48 | function isString(value) {
49 | return typeof value === 'string'
50 | }
51 |
52 |
53 |
54 | function isFunction(value) {
55 | return typeof value === 'function'
56 | }
57 |
58 | function objectExtend(a, b) {
59 |
60 | // Don't touch 'null' or 'undefined' objects.
61 | if (a == null || b == null) {
62 | return a;
63 | }
64 |
65 | Object.keys(b).forEach(function (key) {
66 | if (Object.prototype.toString.call(b[key]) == '[object Object]') {
67 | if (Object.prototype.toString.call(a[key]) != '[object Object]') {
68 | a[key] = b[key];
69 | } else {
70 | a[key] = objectExtend(a[key], b[key]);
71 | }
72 | } else {
73 | a[key] = b[key];
74 | }
75 | });
76 |
77 | return a;
78 | }
79 |
80 | /**
81 | * Assemble url from two segments
82 | *
83 | * @author Sahat Yalkabov
84 | * @copyright Method taken from https://github.com/sahat/satellizer
85 | *
86 | * @param {String} baseUrl Base url
87 | * @param {String} url URI
88 | * @return {String}
89 | */
90 | function joinUrl(baseUrl, url) {
91 | if (/^(?:[a-z]+:)?\/\//i.test(url)) {
92 | return url;
93 | }
94 | var joined = [baseUrl, url].join('/');
95 | var normalize = function (str) {
96 | return str
97 | .replace(/[\/]+/g, '/')
98 | .replace(/\/\?/g, '?')
99 | .replace(/\/\#/g, '#')
100 | .replace(/\:\//g, '://');
101 | };
102 | return normalize(joined);
103 | }
104 |
105 | /**
106 | * Get full path based on current location
107 | *
108 | * @author Sahat Yalkabov
109 | * @copyright Method taken from https://github.com/sahat/satellizer
110 | *
111 | * @param {Location} location
112 | * @return {String}
113 | */
114 | function getFullUrlPath(location) {
115 | var isHttps = location.protocol === 'https:';
116 | return location.protocol + '//' + location.hostname +
117 | ':' + (location.port || (isHttps ? '443' : '80')) +
118 | (/^\//.test(location.pathname) ? location.pathname : '/' + location.pathname);
119 | }
120 |
121 | /**
122 | * Parse query string variables
123 | *
124 | * @author Sahat Yalkabov
125 | * @copyright Method taken from https://github.com/sahat/satellizer
126 | *
127 | * @param {String} Query string
128 | * @return {String}
129 | */
130 | function parseQueryString(str) {
131 | var obj = {};
132 | var key;
133 | var value;
134 | (str || '').split('&').forEach(function (keyValue) {
135 | if (keyValue) {
136 | value = keyValue.split('=');
137 | key = decodeURIComponent(value[0]);
138 | obj[key] = (!!value[1]) ? decodeURIComponent(value[1]) : true;
139 | }
140 | });
141 | return obj;
142 | }
143 |
144 | /**
145 | * Decode base64 string
146 | * @author Sahat Yalkabov
147 | * @copyright Method taken from https://github.com/sahat/satellizer
148 | *
149 | * @param {String} str base64 encoded string
150 | * @return {Object}
151 | */
152 |
153 |
154 | function parseCookies(str) {
155 | if (str.length === 0) { return {}; }
156 | var parsed = {};
157 | var pattern = new RegExp('\\s*;\\s*');
158 | str.split(pattern).forEach(function (i) {
159 | var ref = i.split('=');
160 | var encodedKey = ref[0];
161 | var encodedValue = ref[1];
162 | var key = decodeURIComponent(encodedKey);
163 | var value = decodeURIComponent(encodedValue);
164 | parsed[key] = value;
165 | });
166 | return parsed;
167 | }
168 |
169 | function formatOptions(options) {
170 | var path = options.path;
171 | var domain = options.domain;
172 | var expires = options.expires;
173 | var secure = options.secure;
174 | return [
175 | typeof path === 'undefined' || path === null
176 | ? '' : ';path=' + path,
177 | typeof domain === 'undefined' || domain === null
178 | ? '' : ';domain=' + domain,
179 | typeof expires === 'undefined' || expires === null
180 | ? '' : ';expires=' + expires.toUTCString(),
181 | typeof secure === 'undefined' || secure === null || secure === false
182 | ? '' : ';secure'
183 | ].join('');
184 | }
185 |
186 | function formatCookie(key, value, options) {
187 | return [
188 | encodeURIComponent(key),
189 | '=',
190 | encodeURIComponent(value),
191 | formatOptions(options)
192 | ].join('');
193 | }
194 |
195 | // Store setTimeout reference so promise-polyfill will be unaffected by
196 | // other code modifying setTimeout (like sinon.useFakeTimers())
197 | var setTimeoutFunc = setTimeout;
198 |
199 | function noop() {}
200 |
201 | // Polyfill for Function.prototype.bind
202 | function bind(fn, thisArg) {
203 | return function () {
204 | fn.apply(thisArg, arguments);
205 | };
206 | }
207 |
208 | function Promise$1(fn) {
209 | if (typeof this !== 'object') { throw new TypeError('Promises must be constructed via new'); }
210 | if (typeof fn !== 'function') { throw new TypeError('not a function'); }
211 | this._state = 0;
212 | this._handled = false;
213 | this._value = undefined;
214 | this._deferreds = [];
215 |
216 | doResolve(fn, this);
217 | }
218 |
219 | function handle(self, deferred) {
220 | while (self._state === 3) {
221 | self = self._value;
222 | }
223 | if (self._state === 0) {
224 | self._deferreds.push(deferred);
225 | return;
226 | }
227 | self._handled = true;
228 | Promise$1._immediateFn(function () {
229 | var cb = self._state === 1 ? deferred.onFulfilled : deferred.onRejected;
230 | if (cb === null) {
231 | (self._state === 1 ? resolve : reject)(deferred.promise, self._value);
232 | return;
233 | }
234 | var ret;
235 | try {
236 | ret = cb(self._value);
237 | } catch (e) {
238 | reject(deferred.promise, e);
239 | return;
240 | }
241 | resolve(deferred.promise, ret);
242 | });
243 | }
244 |
245 | function resolve(self, newValue) {
246 | try {
247 | // Promise Resolution Procedure: https://github.com/promises-aplus/promises-spec#the-promise-resolution-procedure
248 | if (newValue === self) { throw new TypeError('A promise cannot be resolved with itself.'); }
249 | if (newValue && (typeof newValue === 'object' || typeof newValue === 'function')) {
250 | var then = newValue.then;
251 | if (newValue instanceof Promise$1) {
252 | self._state = 3;
253 | self._value = newValue;
254 | finale(self);
255 | return;
256 | } else if (typeof then === 'function') {
257 | doResolve(bind(then, newValue), self);
258 | return;
259 | }
260 | }
261 | self._state = 1;
262 | self._value = newValue;
263 | finale(self);
264 | } catch (e) {
265 | reject(self, e);
266 | }
267 | }
268 |
269 | function reject(self, newValue) {
270 | self._state = 2;
271 | self._value = newValue;
272 | finale(self);
273 | }
274 |
275 | function finale(self) {
276 | if (self._state === 2 && self._deferreds.length === 0) {
277 | Promise$1._immediateFn(function() {
278 | if (!self._handled) {
279 | Promise$1._unhandledRejectionFn(self._value);
280 | }
281 | });
282 | }
283 |
284 | for (var i = 0, len = self._deferreds.length; i < len; i++) {
285 | handle(self, self._deferreds[i]);
286 | }
287 | self._deferreds = null;
288 | }
289 |
290 | function Handler(onFulfilled, onRejected, promise) {
291 | this.onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : null;
292 | this.onRejected = typeof onRejected === 'function' ? onRejected : null;
293 | this.promise = promise;
294 | }
295 |
296 | /**
297 | * Take a potentially misbehaving resolver function and make sure
298 | * onFulfilled and onRejected are only called once.
299 | *
300 | * Makes no guarantees about asynchrony.
301 | */
302 | function doResolve(fn, self) {
303 | var done = false;
304 | try {
305 | fn(function (value) {
306 | if (done) { return; }
307 | done = true;
308 | resolve(self, value);
309 | }, function (reason) {
310 | if (done) { return; }
311 | done = true;
312 | reject(self, reason);
313 | });
314 | } catch (ex) {
315 | if (done) { return; }
316 | done = true;
317 | reject(self, ex);
318 | }
319 | }
320 |
321 | Promise$1.prototype['catch'] = function (onRejected) {
322 | return this.then(null, onRejected);
323 | };
324 |
325 | Promise$1.prototype.then = function (onFulfilled, onRejected) {
326 | var prom = new (this.constructor)(noop);
327 |
328 | handle(this, new Handler(onFulfilled, onRejected, prom));
329 | return prom;
330 | };
331 |
332 | Promise$1.all = function (arr) {
333 | var args = Array.prototype.slice.call(arr);
334 |
335 | return new Promise$1(function (resolve, reject) {
336 | if (args.length === 0) { return resolve([]); }
337 | var remaining = args.length;
338 |
339 | function res(i, val) {
340 | try {
341 | if (val && (typeof val === 'object' || typeof val === 'function')) {
342 | var then = val.then;
343 | if (typeof then === 'function') {
344 | then.call(val, function (val) {
345 | res(i, val);
346 | }, reject);
347 | return;
348 | }
349 | }
350 | args[i] = val;
351 | if (--remaining === 0) {
352 | resolve(args);
353 | }
354 | } catch (ex) {
355 | reject(ex);
356 | }
357 | }
358 |
359 | for (var i = 0; i < args.length; i++) {
360 | res(i, args[i]);
361 | }
362 | });
363 | };
364 |
365 | Promise$1.resolve = function (value) {
366 | if (value && typeof value === 'object' && value.constructor === Promise$1) {
367 | return value;
368 | }
369 |
370 | return new Promise$1(function (resolve) {
371 | resolve(value);
372 | });
373 | };
374 |
375 | Promise$1.reject = function (value) {
376 | return new Promise$1(function (resolve, reject) {
377 | reject(value);
378 | });
379 | };
380 |
381 | Promise$1.race = function (values) {
382 | return new Promise$1(function (resolve, reject) {
383 | for (var i = 0, len = values.length; i < len; i++) {
384 | values[i].then(resolve, reject);
385 | }
386 | });
387 | };
388 |
389 | // Use polyfill for setImmediate for performance gains
390 | Promise$1._immediateFn = (typeof setImmediate === 'function' && function (fn) { setImmediate(fn); }) ||
391 | function (fn) {
392 | setTimeoutFunc(fn, 0);
393 | };
394 |
395 | Promise$1._unhandledRejectionFn = function _unhandledRejectionFn(err) {
396 | if (typeof console !== 'undefined' && console) {
397 | console.warn('Possible Unhandled Promise Rejection:', err); // eslint-disable-line no-console
398 | }
399 | };
400 |
401 | /**
402 | * Set the immediate function to execute callbacks
403 | * @param fn {function} Function to execute
404 | * @deprecated
405 | */
406 | Promise$1._setImmediateFn = function _setImmediateFn(fn) {
407 | Promise$1._immediateFn = fn;
408 | };
409 |
410 | /**
411 | * Change the function to execute on unhandled rejection
412 | * @param {function} fn Function to execute on unhandled rejection
413 | * @deprecated
414 | */
415 | Promise$1._setUnhandledRejectionFn = function _setUnhandledRejectionFn(fn) {
416 | Promise$1._unhandledRejectionFn = fn;
417 | };
418 |
419 | /**
420 | * Default configuration
421 | */
422 | var defaultOptions = {
423 | baseUrl: null,
424 | tokenName: 'token',
425 | tokenPrefix: 'vueauth',
426 | tokenHeader: 'Authorization',
427 | tokenType: 'Bearer',
428 | loginUrl: '/auth/login',
429 | registerUrl: '/auth/register',
430 | logoutUrl: null,
431 | storageType: 'localStorage',
432 | storageNamespace: 'vue-social-auth',
433 | cookieStorage: {
434 | domain: window.location.hostname,
435 | path: '/',
436 | secure: false
437 | },
438 | requestDataKey: 'data',
439 | responseDataKey: 'data',
440 |
441 | /**
442 | * Default request interceptor for Axios library
443 | * @context {VueSocialauth}
444 | */
445 | bindRequestInterceptor: function ($auth) {
446 |
447 | var tokenHeader = $auth.options.tokenHeader;
448 |
449 | $auth.$http.interceptors.request.use(function (config) {
450 | delete config.headers[tokenHeader];
451 | return config
452 | });
453 |
454 |
455 | },
456 |
457 | /**
458 | * Default response interceptor for Axios library
459 | * @contect {VueSocialauth}
460 | */
461 | bindResponseInterceptor: function ($auth) {
462 | $auth.$http.interceptors.response.use(function (response) {
463 | return response
464 | });
465 | },
466 |
467 | providers: {
468 | facebook: {
469 | name: 'facebook',
470 | url: '/auth/facebook',
471 | authorizationEndpoint: 'https://www.facebook.com/v2.5/dialog/oauth',
472 | redirectUri: window.location.origin + '/',
473 | requiredUrlParams: ['display', 'scope'],
474 | scope: ['email'],
475 | scopeDelimiter: ',',
476 | display: 'popup',
477 | oauthType: '2.0',
478 | popupOptions: { width: 580, height: 400 }
479 | },
480 |
481 | google: {
482 | name: 'google',
483 | url: '/auth/google',
484 | authorizationEndpoint: 'https://accounts.google.com/o/oauth2/auth',
485 | redirectUri: window.location.origin,
486 | requiredUrlParams: ['scope'],
487 | optionalUrlParams: ['display'],
488 | scope: ['profile', 'email'],
489 | scopePrefix: 'openid',
490 | scopeDelimiter: ' ',
491 | display: 'popup',
492 | oauthType: '2.0',
493 | popupOptions: { width: 452, height: 633 }
494 | },
495 |
496 | github: {
497 | name: 'github',
498 | url: '/auth/github',
499 | authorizationEndpoint: 'https://github.com/login/oauth/authorize',
500 | redirectUri: window.location.origin,
501 | optionalUrlParams: ['scope'],
502 | scope: ['user:email'],
503 | scopeDelimiter: ' ',
504 | oauthType: '2.0',
505 | popupOptions: { width: 1020, height: 618 }
506 | },
507 |
508 | instagram: {
509 | name: 'instagram',
510 | url: '/auth/instagram',
511 | authorizationEndpoint: 'https://api.instagram.com/oauth/authorize',
512 | redirectUri: window.location.origin,
513 | requiredUrlParams: ['scope'],
514 | scope: ['basic'],
515 | scopeDelimiter: '+',
516 | oauthType: '2.0',
517 | popupOptions: { width: null, height: null }
518 | },
519 |
520 | twitter: {
521 | name: 'twitter',
522 | url: '/auth/twitter',
523 | authorizationEndpoint: 'https://api.twitter.com/oauth/authenticate',
524 | redirectUri: window.location.origin,
525 | oauthType: '1.0',
526 | popupOptions: { width: 495, height: 645 }
527 | },
528 |
529 | bitbucket: {
530 | name: 'bitbucket',
531 | url: '/auth/bitbucket',
532 | authorizationEndpoint: 'https://bitbucket.org/site/oauth2/authorize',
533 | redirectUri: window.location.origin + '/',
534 | optionalUrlParams: ['scope'],
535 | scope: ['email'],
536 | scopeDelimiter: ' ',
537 | oauthType: '2.0',
538 | popupOptions: { width: 1020, height: 618 }
539 | },
540 |
541 | linkedin: {
542 | name: 'linkedin',
543 | url: '/auth/linkedin',
544 | authorizationEndpoint: 'https://www.linkedin.com/oauth/v2/authorization',
545 | redirectUri: window.location.origin,
546 | requiredUrlParams: ['state','scope'],
547 | scope: ['r_liteprofile','r_emailaddress'],
548 | scopeDelimiter: ' ',
549 | state: 'STATE',
550 | oauthType: '2.0',
551 | popupOptions: { width: 527, height: 582 }
552 | },
553 |
554 | vkontakte: {
555 | name: 'vkontakte',
556 | url: '/auth/vkontakte',
557 | authorizationEndpoint: 'https://oauth.vk.com/authorize',
558 | redirectUri: window.location.origin + '/',
559 | requiredUrlParams: ['scope'],
560 | scope: ['email'],
561 | scopeDelimiter: ',',
562 | display: 'popup',
563 | oauthType: '2.0',
564 | popupOptions: { width: 580, height: 400 }
565 | },
566 |
567 | live: {
568 | name: 'live',
569 | url: '/auth/live',
570 | authorizationEndpoint: 'https://login.live.com/oauth20_authorize.srf',
571 | redirectUri: window.location.origin,
572 | requiredUrlParams: ['display', 'scope'],
573 | scope: ['wl.emails'],
574 | scopeDelimiter: ' ',
575 | display: 'popup',
576 | oauthType: '2.0',
577 | popupOptions: { width: 500, height: 560 }
578 | },
579 |
580 | oauth1: {
581 | name: null,
582 | url: '/auth/oauth1',
583 | authorizationEndpoint: null,
584 | redirectUri: window.location.origin,
585 | oauthType: '1.0',
586 | popupOptions: null
587 | },
588 |
589 | oauth2: {
590 | name: null,
591 | url: '/auth/oauth2',
592 | clientId: null,
593 | redirectUri: window.location.origin,
594 | authorizationEndpoint: null,
595 | defaultUrlParams: ['response_type', 'client_id', 'redirect_uri'],
596 | requiredUrlParams: null,
597 | optionalUrlParams: null,
598 | scope: null,
599 | scopePrefix: null,
600 | scopeDelimiter: null,
601 | state: null,
602 | oauthType: '2.0',
603 | popupOptions: null,
604 | responseType: 'code',
605 | responseParams: {
606 | code: 'code',
607 | clientId: 'clientId',
608 | redirectUri: 'redirectUri'
609 | }
610 | }
611 | }
612 | };
613 |
614 | var CookieStorage = function CookieStorage(defaultOptions) {
615 | this._defaultOptions = objectExtend({
616 | domain: window.location.hostname,
617 | expires: null,
618 | path: '/',
619 | secure: false
620 | }, defaultOptions);
621 | };
622 |
623 | CookieStorage.prototype.setItem = function setItem (key, value) {
624 | var options = objectExtend({}, this._defaultOptions);
625 | var cookie = formatCookie(key, value, options);
626 | this._setCookie(cookie);
627 | };
628 |
629 | CookieStorage.prototype.getItem = function getItem (key) {
630 | var cookies = parseCookies(this._getCookie());
631 | return cookies.hasOwnProperty(key) ? cookies[key] : null;
632 | };
633 |
634 | CookieStorage.prototype.removeItem = function removeItem (key) {
635 | var value = '';
636 | var defaultOptions = objectExtend({}, this._defaultOptions);
637 | var options = objectExtend(defaultOptions, {
638 | expires: new Date(0)
639 | });
640 | var cookie = formatCookie(key, value, options);
641 | this._setCookie(cookie);
642 | };
643 |
644 | CookieStorage.prototype._getCookie = function _getCookie () {
645 | return typeof document === 'undefined'
646 | ? '' : typeof document.cookie === 'undefined'
647 | ? '' : document.cookie;
648 | };
649 |
650 | CookieStorage.prototype._setCookie = function _setCookie (cookie) {
651 | document.cookie = cookie;
652 | };
653 |
654 | var LocalStorage = function LocalStorage(namespace) {
655 | this.namespace = namespace || null;
656 | };
657 |
658 | LocalStorage.prototype.setItem = function setItem (key, value) {
659 | window.localStorage.setItem(this._getStorageKey(key), value);
660 | };
661 |
662 | LocalStorage.prototype.getItem = function getItem (key) {
663 | return window.localStorage.getItem(this._getStorageKey(key))
664 | };
665 |
666 | LocalStorage.prototype.removeItem = function removeItem (key) {
667 | window.localStorage.removeItem(this._getStorageKey(key));
668 | };
669 |
670 | LocalStorage.prototype._getStorageKey = function _getStorageKey (key) {
671 | if (this.namespace) {
672 | return [this.namespace, key].join('.')
673 | }
674 | return key;
675 | };
676 |
677 | var MemoryStorage = function MemoryStorage(namespace) {
678 | this.namespace = namespace || null;
679 | this._storage = {};
680 | };
681 |
682 | MemoryStorage.prototype.setItem = function setItem (key, value) {
683 | this._storage[this._getStorageKey(key)] = value;
684 | };
685 |
686 | MemoryStorage.prototype.getItem = function getItem (key) {
687 | return this._storage[this._getStorageKey(key)]
688 | };
689 |
690 | MemoryStorage.prototype.removeItem = function removeItem (key) {
691 | delete this._storage[this._getStorageKey(key)];
692 | };
693 |
694 | MemoryStorage.prototype._getStorageKey = function _getStorageKey (key) {
695 | if (this.namespace) {
696 | return [this.namespace, key].join('.')
697 | }
698 | return key;
699 | };
700 |
701 | var LocalStorage$2 = function LocalStorage(namespace) {
702 | this.namespace = namespace || null;
703 | };
704 |
705 | LocalStorage$2.prototype.setItem = function setItem (key, value) {
706 | window.sessionStorage.setItem(this._getStorageKey(key), value);
707 | };
708 |
709 | LocalStorage$2.prototype.getItem = function getItem (key) {
710 | return window.sessionStorage.getItem(this._getStorageKey(key))
711 | };
712 |
713 | LocalStorage$2.prototype.removeItem = function removeItem (key) {
714 | window.sessionStorage.removeItem(this._getStorageKey(key));
715 | };
716 |
717 | LocalStorage$2.prototype._getStorageKey = function _getStorageKey (key) {
718 | if (this.namespace) {
719 | return [this.namespace, key].join('.')
720 | }
721 | return key;
722 | };
723 |
724 | function StorageFactory(options) {
725 | switch (options.storageType) {
726 | case 'localStorage':
727 | try {
728 | window.localStorage.setItem('testKey', 'test');
729 | window.localStorage.removeItem('testKey');
730 | return new LocalStorage(options.storageNamespace)
731 | } catch(e) {}
732 |
733 | case 'sessionStorage':
734 | try {
735 | window.sessionStorage.setItem('testKey', 'test');
736 | window.sessionStorage.removeItem('testKey');
737 | return new LocalStorage$2(options.storageNamespace)
738 | } catch (e) {}
739 |
740 | case 'cookieStorage':
741 | return new CookieStorage(options.cookieStorage);
742 |
743 | case 'memoryStorage':
744 | default:
745 | return new MemoryStorage(options.storageNamespace)
746 | break;
747 | }
748 | }
749 |
750 | /**
751 | * OAuth2 popup management class
752 | *
753 | * @author Sahat Yalkabov
754 | * @copyright Class mostly taken from https://github.com/sahat/satellizer
755 | * and adjusted to fit vue-social-auth library
756 | */
757 | var OAuthPopup = function OAuthPopup(url, name, popupOptions) {
758 | this.popup = null;
759 | this.url = url;
760 | this.name = name;
761 | this.popupOptions = popupOptions;
762 | };
763 |
764 | OAuthPopup.prototype.open = function open (redirectUri, skipPooling) {
765 | try {
766 | this.popup = window.open(this.url, this.name, this._stringifyOptions());
767 | if (this.popup && this.popup.focus) {
768 | this.popup.focus();
769 | }
770 |
771 | if (skipPooling) {
772 | return Promise$1.resolve()
773 | } else {
774 | return this.pooling(redirectUri)
775 | }
776 | } catch(e) {
777 | return Promise$1.reject(new Error('OAuth popup error occurred'))
778 | }
779 | };
780 |
781 | OAuthPopup.prototype.pooling = function pooling (redirectUri) {
782 | var this$1 = this;
783 |
784 | return new Promise$1(function (resolve, reject) {
785 | var redirectUriParser = document.createElement('a');
786 | redirectUriParser.href = redirectUri;
787 | var redirectUriPath = getFullUrlPath(redirectUriParser);
788 |
789 | var poolingInterval = setInterval(function () {
790 | if (!this$1.popup || this$1.popup.closed || this$1.popup.closed === undefined) {
791 | clearInterval(poolingInterval);
792 | poolingInterval = null;
793 | reject(new Error('Auth popup window closed'));
794 | }
795 |
796 | try {
797 | var popupWindowPath = getFullUrlPath(this$1.popup.location);
798 |
799 | if (popupWindowPath === redirectUriPath) {
800 | if (this$1.popup.location.search || this$1.popup.location.hash) {
801 | var query = parseQueryString(this$1.popup.location.search.substring(1).replace(/\/$/, ''));
802 | var hash = parseQueryString(this$1.popup.location.hash.substring(1).replace(/[\/$]/, ''));
803 | var params = objectExtend({}, query);
804 | params = objectExtend(params, hash);
805 |
806 | if (params.error) {
807 | reject(new Error(params.error));
808 | } else {
809 | resolve(params);
810 | }
811 | } else {
812 | reject(new Error('OAuth redirect has occurred but no query or hash parameters were found.'));
813 | }
814 |
815 | clearInterval(poolingInterval);
816 | poolingInterval = null;
817 | this$1.popup.close();
818 | }
819 | } catch(e) {
820 | // Ignore DOMException: Blocked a frame with origin from accessing a cross-origin frame.
821 | }
822 | }, 250);
823 | })
824 | };
825 |
826 | OAuthPopup.prototype._stringifyOptions = function _stringifyOptions () {
827 | var this$1 = this;
828 |
829 | var options = [];
830 | for (var optionKey in this$1.popupOptions) {
831 | if (!isUndefined(this$1.popupOptions[optionKey])) {
832 | options.push((optionKey + "=" + (this$1.popupOptions[optionKey])));
833 | }
834 | }
835 | return options.join(',')
836 | };
837 |
838 | var defaultProviderConfig = {
839 | name: null,
840 | url: null,
841 | authorizationEndpoint: null,
842 | scope: null,
843 | scopePrefix: null,
844 | scopeDelimiter: null,
845 | redirectUri: null,
846 | requiredUrlParams: null,
847 | defaultUrlParams: null,
848 | oauthType: '1.0',
849 | popupOptions: {}
850 | };
851 |
852 | var OAuth = function OAuth($http, storage, providerConfig, options) {
853 | this.$http = $http;
854 | this.storage = storage;
855 | this.providerConfig = objectExtend({}, defaultProviderConfig);
856 | this.providerConfig = objectExtend(this.providerConfig, providerConfig);
857 | this.options = options;
858 | };
859 |
860 | /**
861 | * Initialize OAuth1 process
862 | * @param{Object} userData User data
863 | * @return {Promise}
864 | */
865 | OAuth.prototype.init = function init (userData) {
866 | var this$1 = this;
867 |
868 | this.oauthPopup = new OAuthPopup('about:blank', this.providerConfig.name, this.providerConfig.popupOptions);
869 |
870 | if (window && !window['cordova']) {
871 | this.oauthPopup.open(this.providerConfig.redirectUri, true);
872 | }
873 |
874 | return this.getRequestToken().then(function (response) {
875 | return this$1.openPopup(response).then(function (popupResponse) {
876 | return this$1.exchangeForToken(popupResponse, userData)
877 | })
878 | })
879 | };
880 |
881 | /**
882 | * Get OAuth1 request token
883 | * @return {Promise}
884 | */
885 | OAuth.prototype.getRequestToken = function getRequestToken () {
886 | var requestOptions = {};
887 | requestOptions.method = 'POST';
888 | requestOptions[this.options.requestDataKey] = objectExtend({}, this.providerConfig);
889 | requestOptions.withCredentials = this.options.withCredentials;
890 | if (this.options.baseUrl) {
891 | requestOptions.url = joinUrl(this.options.baseUrl, this.providerConfig.url);
892 | } else {
893 | requestOptions.url = this.providerConfig.url;
894 | }
895 |
896 | return this.$http(requestOptions)
897 | };
898 |
899 | /**
900 | * Open OAuth1 popup
901 | * @param{Object} response Response object containing request token
902 | * @return {Promise}
903 | */
904 | OAuth.prototype.openPopup = function openPopup (response) {
905 | var url = [this.providerConfig.authorizationEndpoint, this.buildQueryString(response[this.options.responseDataKey])].join('?');
906 |
907 | this.oauthPopup.popup.location = url;
908 | if (window && window['cordova']) {
909 | return this.oauthPopup.open(this.providerConfig.redirectUri)
910 | } else {
911 | return this.oauthPopup.pooling(this.providerConfig.redirectUri)
912 | }
913 | };
914 |
915 | /**
916 | * Exchange token and token verifier for access token
917 | * @param{Object} oauth OAuth data containing token and token verifier
918 | * @param{Object} userData User data
919 | * @return {Promise}
920 | */
921 | OAuth.prototype.exchangeForToken = function exchangeForToken (oauth, userData) {
922 | var payload = objectExtend({}, userData);
923 | payload = objectExtend(payload, oauth);
924 | var requestOptions = {};
925 | requestOptions.method = 'POST';
926 | requestOptions[this.options.requestDataKey] = payload;
927 | requestOptions.withCredentials = this.options.withCredentials;
928 | if (this.options.baseUrl) {
929 | requestOptions.url = joinUrl(this.options.baseUrl, this.providerConfig.url);
930 | } else {
931 | requestOptions.url = this.providerConfig.url;
932 | }
933 | return this.$http(requestOptions)
934 | };
935 |
936 | OAuth.prototype.buildQueryString = function buildQueryString (params) {
937 | var parsedParams = [];
938 | for (var key in params) {
939 | var value = params[key];
940 | parsedParams.push(encodeURIComponent(key) + '=' + encodeURIComponent(value));
941 | }
942 | return parsedParams.join('&');
943 | };
944 |
945 | /**
946 | * Default provider configuration
947 | * @type {Object}
948 | */
949 | var defaultProviderConfig$1 = {
950 | name: null,
951 | url: null,
952 | clientId: null,
953 | authorizationEndpoint: null,
954 | redirectUri: null,
955 | scope: null,
956 | scopePrefix: null,
957 | scopeDelimiter: null,
958 | state: null,
959 | requiredUrlParams: null,
960 | defaultUrlParams: ['response_type', 'client_id', 'redirect_uri'],
961 | responseType: 'code',
962 | responseParams: {
963 | code: 'code',
964 | clientId: 'clientId',
965 | redirectUri: 'redirectUri'
966 | },
967 | oauthType: '2.0',
968 | popupOptions: {}
969 | };
970 |
971 | var OAuth2 = function OAuth2($http, storage, providerConfig, options) {
972 | this.$http = $http;
973 | this.storage = storage;
974 | this.providerConfig = objectExtend({}, defaultProviderConfig$1);
975 | this.providerConfig = objectExtend(this.providerConfig, providerConfig);
976 | this.options = options;
977 | };
978 |
979 | OAuth2.prototype.init = function init (userData) {
980 | var this$1 = this;
981 |
982 | var stateName = this.providerConfig.name + '_state';
983 | if (isFunction(this.providerConfig.state)) {
984 | this.storage.setItem(stateName, this.providerConfig.state());
985 | } else if (isString(this.providerConfig.state)) {
986 | this.storage.setItem(stateName, this.providerConfig.state);
987 | }
988 |
989 | var url = [this.providerConfig.authorizationEndpoint, this._stringifyRequestParams()].join('?');
990 |
991 | this.oauthPopup = new OAuthPopup(url, this.providerConfig.name, this.providerConfig.popupOptions);
992 |
993 | return new Promise(function (resolve, reject) {
994 | this$1.oauthPopup.open(this$1.providerConfig.redirectUri).then(function (response) {
995 | if (this$1.providerConfig.responseType === 'code' || !this$1.providerConfig.url) {
996 | return resolve(response)
997 | }
998 |
999 | if (response.state && response.state !== this$1.storage.getItem(stateName)) {
1000 | return reject(new Error('State parameter value does not match original OAuth request state value'))
1001 | }
1002 |
1003 | resolve(this$1.exchangeForToken(response, userData));
1004 | }).catch(function (err) {
1005 | reject(err);
1006 | });
1007 | })
1008 | };
1009 |
1010 | /**
1011 | * Exchange temporary oauth data for access token
1012 | * @author Sahat Yalkabov
1013 | * @copyright Method taken from https://github.com/sahat/satellizer
1014 | *
1015 | * @param{[type]} oauth [description]
1016 | * @param{[type]} userData [description]
1017 | * @return {[type]} [description]
1018 | */
1019 | OAuth2.prototype.exchangeForToken = function exchangeForToken (oauth, userData) {
1020 | var this$1 = this;
1021 |
1022 | var payload = objectExtend({}, userData);
1023 |
1024 | for (var key in defaultProviderConfig$1.responseParams) {
1025 | var value = defaultProviderConfig$1[key];
1026 |
1027 | switch(key) {
1028 | case 'code':
1029 | payload[key] = oauth.code;
1030 | break
1031 | case 'clientId':
1032 | payload[key] = this$1.providerConfig.clientId;
1033 | break
1034 | case 'redirectUri':
1035 | payload[key] = this$1.providerConfig.redirectUri;
1036 | break
1037 | default:
1038 | payload[key] = oauth[key];
1039 | }
1040 | }
1041 |
1042 | if (oauth.state) {
1043 | payload.state = oauth.state;
1044 | }
1045 |
1046 | var exchangeTokenUrl;
1047 | if (this.options.baseUrl) {
1048 | exchangeTokenUrl = joinUrl(this.options.baseUrl, this.providerConfig.url);
1049 | } else {
1050 | exchangeTokenUrl = this.providerConfig.url;
1051 | }
1052 |
1053 | return this.$http.post(exchangeTokenUrl, payload, {
1054 | withCredentials: this.options.withCredentials
1055 | })
1056 | };
1057 |
1058 | /**
1059 | * Stringify oauth params
1060 | * @author Sahat Yalkabov
1061 | * @copyright Method taken from https://github.com/sahat/satellizer
1062 | *
1063 | * @return {String}
1064 | */
1065 | OAuth2.prototype._stringifyRequestParams = function _stringifyRequestParams () {
1066 | var this$1 = this;
1067 |
1068 | var keyValuePairs = [];
1069 | var paramCategories = ['defaultUrlParams', 'requiredUrlParams', 'optionalUrlParams'];
1070 |
1071 | paramCategories.forEach(function (categoryName) {
1072 | if (!this$1.providerConfig[categoryName]) { return }
1073 | if (!Array.isArray(this$1.providerConfig[categoryName])) { return }
1074 |
1075 | this$1.providerConfig[categoryName].forEach(function (paramName) {
1076 | var camelCaseParamName = camelCase(paramName);
1077 | var paramValue = isFunction(this$1.providerConfig[paramName]) ? this$1.providerConfig[paramName]() : this$1.providerConfig[camelCaseParamName];
1078 |
1079 | if (paramName === 'redirect_uri' && !paramValue) { return }
1080 |
1081 | if (paramName === 'state') {
1082 | var stateName = this$1.providerConfig.name + '_state';
1083 | paramValue = encodeURIComponent(this$1.storage.getItem(stateName));
1084 | }
1085 | if (paramName === 'scope' && Array.isArray(paramValue)) {
1086 | paramValue = paramValue.join(this$1.providerConfig.scopeDelimiter);
1087 | if (this$1.providerConfig.scopePrefix) {
1088 | paramValue = [this$1.providerConfig.scopePrefix, paramValue].join(this$1.providerConfig.scopeDelimiter);
1089 | }
1090 | }
1091 |
1092 | keyValuePairs.push([paramName, paramValue]);
1093 | });
1094 | });
1095 |
1096 | return keyValuePairs.map(function (param) {
1097 | return param.join('=')
1098 | }).join('&')
1099 | };
1100 |
1101 | var VueSocialauth = function VueSocialauth($http, overrideOptions) {
1102 | var options = objectExtend({}, defaultOptions);
1103 | options = objectExtend(options, overrideOptions);
1104 | var storage = StorageFactory(options);
1105 |
1106 | Object.defineProperties(this, {
1107 | $http: {
1108 | get: function get() {
1109 | return $http
1110 | }
1111 | },
1112 |
1113 | options: {
1114 | get: function get() {
1115 | return options
1116 | }
1117 | },
1118 |
1119 | storage: {
1120 | get: function get() {
1121 | return storage
1122 | }
1123 | },
1124 |
1125 | tokenName: {
1126 | get: function get() {
1127 | if (this.options.tokenPrefix) {
1128 | return [this.options.tokenPrefix, this.options.tokenName].join('_')
1129 | } else {
1130 | return this.options.tokenName
1131 | }
1132 | }
1133 | }
1134 | });
1135 |
1136 | // Setup request interceptors
1137 | if (this.options.bindRequestInterceptor && isFunction(this.options.bindRequestInterceptor) &&
1138 | this.options.bindResponseInterceptor && isFunction(this.options.bindResponseInterceptor)) {
1139 |
1140 | this.options.bindRequestInterceptor.call(this, this);
1141 | this.options.bindResponseInterceptor.call(this, this);
1142 | } else {
1143 | throw new Error('Both request and response interceptors must be functions')
1144 | }
1145 | };
1146 |
1147 | /**
1148 | * Check if user is authenticated
1149 | * @author Sahat Yalkabov
1150 | * @copyright Method taken from https://github.com/sahat/satellizer
1151 | * @return {Boolean}
1152 | */
1153 | // isAuthenticated() {
1154 | // let token = this.storage.getItem(this.tokenName)
1155 |
1156 | // if (token) {// Token is present
1157 | // if (token.split('.').length === 3) {// Token with a valid JWT format XXX.YYY.ZZZ
1158 | // try { // Could be a valid JWT or an access token with the same format
1159 | // const base64Url = token.split('.')[1];
1160 | // const base64 = base64Url.replace('-', '+').replace('_', '/');
1161 | // const exp = JSON.parse(window.atob(base64)).exp;
1162 | // if (typeof exp === 'number') {// JWT with an optonal expiration claims
1163 | // return Math.round(new Date().getTime() / 1000) < exp;
1164 | // }
1165 | // } catch (e) {
1166 | // return true;// Pass: Non-JWT token that looks like JWT
1167 | // }
1168 | // }
1169 | // return true;// Pass: All other tokens
1170 | // }
1171 | // return false
1172 | // }
1173 |
1174 | /**
1175 | * Get token if user is authenticated
1176 | * @return {String} Authentication token
1177 | */
1178 | VueSocialauth.prototype.getToken = function getToken () {
1179 | return this.storage.getItem(this.tokenName)
1180 | };
1181 |
1182 | /**
1183 | * Set new authentication token
1184 | * @param {String|Object} token
1185 | */
1186 | // setToken(response) {
1187 | // if (response[this.options.responseDataKey]) {
1188 | // response = response[this.options.responseDataKey];
1189 | // }
1190 |
1191 | // let token;
1192 | // if (response.access_token) {
1193 | // if (isObject(response.access_token) && isObject(response.access_token[this.options.responseDataKey])) {
1194 | // response = response.access_token
1195 | // } else if (isString(response.access_token)) {
1196 | // token = response.access_token
1197 | // }
1198 | // }
1199 |
1200 | // if (!token && response) {
1201 | // token = response[this.options.tokenName]
1202 | // }
1203 |
1204 | // if (token) {
1205 | // this.storage.setItem(this.tokenName, token)
1206 | // }
1207 | // }
1208 |
1209 | // getPayload() {
1210 | // const token = this.storage.getItem(this.tokenName);
1211 |
1212 | // if (token && token.split('.').length === 3) {
1213 | // try {
1214 | // const base64Url = token.split('.')[1];
1215 | // const base64 = base64Url.replace('-', '+').replace('_', '/');
1216 | // return JSON.parse(decodeBase64(base64));
1217 | // } catch (e) {}
1218 | // }
1219 | // }
1220 |
1221 | /**
1222 | * Login user using email and password
1223 | * @param{Object} user User data
1224 | * @param{Object} requestOptions Request options
1225 | * @return {Promise} Request promise
1226 | */
1227 | // login(user, requestOptions) {
1228 | // requestOptions = requestOptions || {}
1229 | // requestOptions.url = requestOptions.url ? requestOptions.url : joinUrl(this.options.baseUrl, this.options.loginUrl)
1230 | // requestOptions[this.options.requestDataKey] = user || requestOptions[this.options.requestDataKey]
1231 | // requestOptions.method = requestOptions.method || 'POST'
1232 | // requestOptions.withCredentials = requestOptions.withCredentials || this.options.withCredentials
1233 |
1234 | // return this.$http(requestOptions).then((response) => {
1235 | // this.setToken(response)
1236 | // return response
1237 | // })
1238 | // }
1239 |
1240 | /**
1241 | * Register new user
1242 | * @param{Object} user User data
1243 | * @param{Object} requestOptions Request options
1244 | * @return {Promise} Request promise
1245 | */
1246 | // register(user, requestOptions) {
1247 | // requestOptions = requestOptions || {}
1248 | // requestOptions.url = requestOptions.url ? requestOptions.url : joinUrl(this.options.baseUrl, this.options.registerUrl)
1249 | // requestOptions[this.options.requestDataKey] = user || requestOptions[this.options.requestDataKey]
1250 | // requestOptions.method = requestOptions.method || 'POST'
1251 | // requestOptions.withCredentials = requestOptions.withCredentials || this.options.withCredentials
1252 |
1253 | // return this.$http(requestOptions).then((response) => {
1254 | // this.setToken(response)
1255 | // return response
1256 | // })
1257 | // }
1258 |
1259 | /**
1260 | * Logout current user
1261 | * @param{Object} requestOptionsLogout request options object
1262 | * @return {Promise} Request promise
1263 | */
1264 | // logout(requestOptions) {
1265 | // if (!this.isAuthenticated()) {
1266 | // return Promise.reject(new Error('There is no currently authenticated user'))
1267 | // }
1268 |
1269 | // requestOptions = requestOptions || {}
1270 | // requestOptions.url = requestOptions.logoutUrl || this.options.logoutUrl
1271 |
1272 | // if (requestOptions.url) {
1273 | // requestOptions.method = requestOptions.method || 'POST'
1274 | // requestOptions.withCredentials = requestOptions.withCredentials || this.options.withCredentials
1275 |
1276 | // return this.$http(requestOptions).then((response) => {
1277 | // this.storage.removeItem(this.tokenName)
1278 | // })
1279 | // } else {
1280 | // this.storage.removeItem(this.tokenName)
1281 | // return Promise.resolve();
1282 | // }
1283 | // }
1284 |
1285 | /**
1286 | * Authenticate user using authentication provider
1287 | *
1288 | * @param{String} provider Provider name
1289 | * @param{Object} userData User data
1290 | * @param{Object} requestOptions Request options
1291 | * @return {Promise} Request promise
1292 | */
1293 | VueSocialauth.prototype.authenticate = function authenticate (provider, userData, requestOptions) {
1294 | var this$1 = this;
1295 |
1296 | return new Promise$1(function (resolve, reject) {
1297 | var providerConfig = this$1.options.providers[provider];
1298 | if (!providerConfig) {
1299 | return reject(new Error('Unknown provider'))
1300 | }
1301 |
1302 | var providerInstance;
1303 | switch (providerConfig.oauthType) {
1304 | case '1.0':
1305 | providerInstance = new OAuth(this$1.$http, this$1.storage, providerConfig, this$1.options);
1306 | break
1307 | case '2.0':
1308 | providerInstance = new OAuth2(this$1.$http, this$1.storage, providerConfig, this$1.options);
1309 | break
1310 | default:
1311 | return reject(new Error('Invalid OAuth type'))
1312 | break
1313 | }
1314 |
1315 | return providerInstance.init(userData).then(function (response) {
1316 | return resolve(response)
1317 |
1318 | }).catch(function (err) { return reject(err); })
1319 | })
1320 | };
1321 |
1322 | /**
1323 | * VueSocialauth plugin
1324 | * @param {Object} Vue
1325 | * @param {Object} options
1326 | */
1327 | function plugin(Vue, options) {
1328 | if (plugin.installed) {
1329 | return
1330 | }
1331 | plugin.installed = true;
1332 |
1333 | var property = options.property || '$auth';
1334 |
1335 | var vueAuthInstance = null;
1336 | Object.defineProperties(Vue.prototype, ( obj = {}, obj[property] = {
1337 | get: function get() {
1338 | if (!vueAuthInstance) {
1339 | // Request handler library not found, throw error
1340 | // verified vue or nuxt instance
1341 | if (this.$axios) {
1342 | vueAuthInstance = new VueSocialauth(this.$axios, options);
1343 | } else if (this.$http) {
1344 | vueAuthInstance = new VueSocialauth(this.$http, options);
1345 | } else {
1346 | throw new Error('Request handler instance not found')
1347 | }
1348 | }
1349 | return vueAuthInstance
1350 | }
1351 | }, obj ));
1352 | var obj;
1353 | }
1354 |
1355 | /**
1356 | * External factory helper for ES5 and CommonJS
1357 | * @param {Object} $http Instance of request handling library
1358 | * @param {Object} options Configuration object
1359 | * @return {VueSocialauth} VueSocialauth instance
1360 | */
1361 | plugin.factory = function ($http, options) {
1362 | return new VueSocialauth($http, options)
1363 | };
1364 |
1365 | export default plugin;
1366 | export { VueSocialauth };
1367 |
--------------------------------------------------------------------------------
/dist/vue-social-auth.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * vue-social-auth v0.0.1
3 | * https://github.com/diadal/vue-social-auth
4 | * Released under the MIT License.
5 | */
6 |
7 | (function (global, factory) {
8 | typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
9 | typeof define === 'function' && define.amd ? define(factory) :
10 | (global.VueSocialauth = factory());
11 | }(this, (function () { 'use strict';
12 |
13 | if (typeof Object.assign != 'function') {
14 | Object.assign = function(target, varArgs) {
15 | 'use strict';
16 | var arguments$1 = arguments;
17 |
18 | if (target == null) {
19 | throw new TypeError('Cannot convert undefined or null to object');
20 | }
21 |
22 | var to = Object(target);
23 |
24 | for (var index = 1; index < arguments.length; index++) {
25 | var nextSource = arguments$1[index];
26 |
27 | if (nextSource != null) { // Skip over if undefined or null
28 | for (var nextKey in nextSource) {
29 | // Avoid bugs when hasOwnProperty is shadowed
30 | if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) {
31 | to[nextKey] = nextSource[nextKey];
32 | }
33 | }
34 | }
35 | }
36 | return to;
37 | };
38 | }
39 |
40 | function camelCase(name) {
41 | return name.replace(/([\:\-\_]+(.))/g, function (_, separator, letter, offset) {
42 | return offset ? letter.toUpperCase() : letter;
43 | });
44 | }
45 |
46 | function isUndefined(value) {
47 | return typeof value === 'undefined'
48 | }
49 |
50 |
51 |
52 |
53 |
54 | function isString(value) {
55 | return typeof value === 'string'
56 | }
57 |
58 |
59 |
60 | function isFunction(value) {
61 | return typeof value === 'function'
62 | }
63 |
64 | function objectExtend(a, b) {
65 |
66 | // Don't touch 'null' or 'undefined' objects.
67 | if (a == null || b == null) {
68 | return a;
69 | }
70 |
71 | Object.keys(b).forEach(function (key) {
72 | if (Object.prototype.toString.call(b[key]) == '[object Object]') {
73 | if (Object.prototype.toString.call(a[key]) != '[object Object]') {
74 | a[key] = b[key];
75 | } else {
76 | a[key] = objectExtend(a[key], b[key]);
77 | }
78 | } else {
79 | a[key] = b[key];
80 | }
81 | });
82 |
83 | return a;
84 | }
85 |
86 | /**
87 | * Assemble url from two segments
88 | *
89 | * @author Sahat Yalkabov
90 | * @copyright Method taken from https://github.com/sahat/satellizer
91 | *
92 | * @param {String} baseUrl Base url
93 | * @param {String} url URI
94 | * @return {String}
95 | */
96 | function joinUrl(baseUrl, url) {
97 | if (/^(?:[a-z]+:)?\/\//i.test(url)) {
98 | return url;
99 | }
100 | var joined = [baseUrl, url].join('/');
101 | var normalize = function (str) {
102 | return str
103 | .replace(/[\/]+/g, '/')
104 | .replace(/\/\?/g, '?')
105 | .replace(/\/\#/g, '#')
106 | .replace(/\:\//g, '://');
107 | };
108 | return normalize(joined);
109 | }
110 |
111 | /**
112 | * Get full path based on current location
113 | *
114 | * @author Sahat Yalkabov
115 | * @copyright Method taken from https://github.com/sahat/satellizer
116 | *
117 | * @param {Location} location
118 | * @return {String}
119 | */
120 | function getFullUrlPath(location) {
121 | var isHttps = location.protocol === 'https:';
122 | return location.protocol + '//' + location.hostname +
123 | ':' + (location.port || (isHttps ? '443' : '80')) +
124 | (/^\//.test(location.pathname) ? location.pathname : '/' + location.pathname);
125 | }
126 |
127 | /**
128 | * Parse query string variables
129 | *
130 | * @author Sahat Yalkabov
131 | * @copyright Method taken from https://github.com/sahat/satellizer
132 | *
133 | * @param {String} Query string
134 | * @return {String}
135 | */
136 | function parseQueryString(str) {
137 | var obj = {};
138 | var key;
139 | var value;
140 | (str || '').split('&').forEach(function (keyValue) {
141 | if (keyValue) {
142 | value = keyValue.split('=');
143 | key = decodeURIComponent(value[0]);
144 | obj[key] = (!!value[1]) ? decodeURIComponent(value[1]) : true;
145 | }
146 | });
147 | return obj;
148 | }
149 |
150 | /**
151 | * Decode base64 string
152 | * @author Sahat Yalkabov
153 | * @copyright Method taken from https://github.com/sahat/satellizer
154 | *
155 | * @param {String} str base64 encoded string
156 | * @return {Object}
157 | */
158 |
159 |
160 | function parseCookies(str) {
161 | if (str.length === 0) { return {}; }
162 | var parsed = {};
163 | var pattern = new RegExp('\\s*;\\s*');
164 | str.split(pattern).forEach(function (i) {
165 | var ref = i.split('=');
166 | var encodedKey = ref[0];
167 | var encodedValue = ref[1];
168 | var key = decodeURIComponent(encodedKey);
169 | var value = decodeURIComponent(encodedValue);
170 | parsed[key] = value;
171 | });
172 | return parsed;
173 | }
174 |
175 | function formatOptions(options) {
176 | var path = options.path;
177 | var domain = options.domain;
178 | var expires = options.expires;
179 | var secure = options.secure;
180 | return [
181 | typeof path === 'undefined' || path === null
182 | ? '' : ';path=' + path,
183 | typeof domain === 'undefined' || domain === null
184 | ? '' : ';domain=' + domain,
185 | typeof expires === 'undefined' || expires === null
186 | ? '' : ';expires=' + expires.toUTCString(),
187 | typeof secure === 'undefined' || secure === null || secure === false
188 | ? '' : ';secure'
189 | ].join('');
190 | }
191 |
192 | function formatCookie(key, value, options) {
193 | return [
194 | encodeURIComponent(key),
195 | '=',
196 | encodeURIComponent(value),
197 | formatOptions(options)
198 | ].join('');
199 | }
200 |
201 | // Store setTimeout reference so promise-polyfill will be unaffected by
202 | // other code modifying setTimeout (like sinon.useFakeTimers())
203 | var setTimeoutFunc = setTimeout;
204 |
205 | function noop() {}
206 |
207 | // Polyfill for Function.prototype.bind
208 | function bind(fn, thisArg) {
209 | return function () {
210 | fn.apply(thisArg, arguments);
211 | };
212 | }
213 |
214 | function Promise$1(fn) {
215 | if (typeof this !== 'object') { throw new TypeError('Promises must be constructed via new'); }
216 | if (typeof fn !== 'function') { throw new TypeError('not a function'); }
217 | this._state = 0;
218 | this._handled = false;
219 | this._value = undefined;
220 | this._deferreds = [];
221 |
222 | doResolve(fn, this);
223 | }
224 |
225 | function handle(self, deferred) {
226 | while (self._state === 3) {
227 | self = self._value;
228 | }
229 | if (self._state === 0) {
230 | self._deferreds.push(deferred);
231 | return;
232 | }
233 | self._handled = true;
234 | Promise$1._immediateFn(function () {
235 | var cb = self._state === 1 ? deferred.onFulfilled : deferred.onRejected;
236 | if (cb === null) {
237 | (self._state === 1 ? resolve : reject)(deferred.promise, self._value);
238 | return;
239 | }
240 | var ret;
241 | try {
242 | ret = cb(self._value);
243 | } catch (e) {
244 | reject(deferred.promise, e);
245 | return;
246 | }
247 | resolve(deferred.promise, ret);
248 | });
249 | }
250 |
251 | function resolve(self, newValue) {
252 | try {
253 | // Promise Resolution Procedure: https://github.com/promises-aplus/promises-spec#the-promise-resolution-procedure
254 | if (newValue === self) { throw new TypeError('A promise cannot be resolved with itself.'); }
255 | if (newValue && (typeof newValue === 'object' || typeof newValue === 'function')) {
256 | var then = newValue.then;
257 | if (newValue instanceof Promise$1) {
258 | self._state = 3;
259 | self._value = newValue;
260 | finale(self);
261 | return;
262 | } else if (typeof then === 'function') {
263 | doResolve(bind(then, newValue), self);
264 | return;
265 | }
266 | }
267 | self._state = 1;
268 | self._value = newValue;
269 | finale(self);
270 | } catch (e) {
271 | reject(self, e);
272 | }
273 | }
274 |
275 | function reject(self, newValue) {
276 | self._state = 2;
277 | self._value = newValue;
278 | finale(self);
279 | }
280 |
281 | function finale(self) {
282 | if (self._state === 2 && self._deferreds.length === 0) {
283 | Promise$1._immediateFn(function() {
284 | if (!self._handled) {
285 | Promise$1._unhandledRejectionFn(self._value);
286 | }
287 | });
288 | }
289 |
290 | for (var i = 0, len = self._deferreds.length; i < len; i++) {
291 | handle(self, self._deferreds[i]);
292 | }
293 | self._deferreds = null;
294 | }
295 |
296 | function Handler(onFulfilled, onRejected, promise) {
297 | this.onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : null;
298 | this.onRejected = typeof onRejected === 'function' ? onRejected : null;
299 | this.promise = promise;
300 | }
301 |
302 | /**
303 | * Take a potentially misbehaving resolver function and make sure
304 | * onFulfilled and onRejected are only called once.
305 | *
306 | * Makes no guarantees about asynchrony.
307 | */
308 | function doResolve(fn, self) {
309 | var done = false;
310 | try {
311 | fn(function (value) {
312 | if (done) { return; }
313 | done = true;
314 | resolve(self, value);
315 | }, function (reason) {
316 | if (done) { return; }
317 | done = true;
318 | reject(self, reason);
319 | });
320 | } catch (ex) {
321 | if (done) { return; }
322 | done = true;
323 | reject(self, ex);
324 | }
325 | }
326 |
327 | Promise$1.prototype['catch'] = function (onRejected) {
328 | return this.then(null, onRejected);
329 | };
330 |
331 | Promise$1.prototype.then = function (onFulfilled, onRejected) {
332 | var prom = new (this.constructor)(noop);
333 |
334 | handle(this, new Handler(onFulfilled, onRejected, prom));
335 | return prom;
336 | };
337 |
338 | Promise$1.all = function (arr) {
339 | var args = Array.prototype.slice.call(arr);
340 |
341 | return new Promise$1(function (resolve, reject) {
342 | if (args.length === 0) { return resolve([]); }
343 | var remaining = args.length;
344 |
345 | function res(i, val) {
346 | try {
347 | if (val && (typeof val === 'object' || typeof val === 'function')) {
348 | var then = val.then;
349 | if (typeof then === 'function') {
350 | then.call(val, function (val) {
351 | res(i, val);
352 | }, reject);
353 | return;
354 | }
355 | }
356 | args[i] = val;
357 | if (--remaining === 0) {
358 | resolve(args);
359 | }
360 | } catch (ex) {
361 | reject(ex);
362 | }
363 | }
364 |
365 | for (var i = 0; i < args.length; i++) {
366 | res(i, args[i]);
367 | }
368 | });
369 | };
370 |
371 | Promise$1.resolve = function (value) {
372 | if (value && typeof value === 'object' && value.constructor === Promise$1) {
373 | return value;
374 | }
375 |
376 | return new Promise$1(function (resolve) {
377 | resolve(value);
378 | });
379 | };
380 |
381 | Promise$1.reject = function (value) {
382 | return new Promise$1(function (resolve, reject) {
383 | reject(value);
384 | });
385 | };
386 |
387 | Promise$1.race = function (values) {
388 | return new Promise$1(function (resolve, reject) {
389 | for (var i = 0, len = values.length; i < len; i++) {
390 | values[i].then(resolve, reject);
391 | }
392 | });
393 | };
394 |
395 | // Use polyfill for setImmediate for performance gains
396 | Promise$1._immediateFn = (typeof setImmediate === 'function' && function (fn) { setImmediate(fn); }) ||
397 | function (fn) {
398 | setTimeoutFunc(fn, 0);
399 | };
400 |
401 | Promise$1._unhandledRejectionFn = function _unhandledRejectionFn(err) {
402 | if (typeof console !== 'undefined' && console) {
403 | console.warn('Possible Unhandled Promise Rejection:', err); // eslint-disable-line no-console
404 | }
405 | };
406 |
407 | /**
408 | * Set the immediate function to execute callbacks
409 | * @param fn {function} Function to execute
410 | * @deprecated
411 | */
412 | Promise$1._setImmediateFn = function _setImmediateFn(fn) {
413 | Promise$1._immediateFn = fn;
414 | };
415 |
416 | /**
417 | * Change the function to execute on unhandled rejection
418 | * @param {function} fn Function to execute on unhandled rejection
419 | * @deprecated
420 | */
421 | Promise$1._setUnhandledRejectionFn = function _setUnhandledRejectionFn(fn) {
422 | Promise$1._unhandledRejectionFn = fn;
423 | };
424 |
425 | /**
426 | * Default configuration
427 | */
428 | var defaultOptions = {
429 | baseUrl: null,
430 | tokenName: 'token',
431 | tokenPrefix: 'vueauth',
432 | tokenHeader: 'Authorization',
433 | tokenType: 'Bearer',
434 | loginUrl: '/auth/login',
435 | registerUrl: '/auth/register',
436 | logoutUrl: null,
437 | storageType: 'localStorage',
438 | storageNamespace: 'vue-social-auth',
439 | cookieStorage: {
440 | domain: window.location.hostname,
441 | path: '/',
442 | secure: false
443 | },
444 | requestDataKey: 'data',
445 | responseDataKey: 'data',
446 |
447 | /**
448 | * Default request interceptor for Axios library
449 | * @context {VueSocialauth}
450 | */
451 | bindRequestInterceptor: function ($auth) {
452 |
453 | var tokenHeader = $auth.options.tokenHeader;
454 |
455 | $auth.$http.interceptors.request.use(function (config) {
456 | delete config.headers[tokenHeader];
457 | return config
458 | });
459 |
460 |
461 | },
462 |
463 | /**
464 | * Default response interceptor for Axios library
465 | * @contect {VueSocialauth}
466 | */
467 | bindResponseInterceptor: function ($auth) {
468 | $auth.$http.interceptors.response.use(function (response) {
469 | return response
470 | });
471 | },
472 |
473 | providers: {
474 | facebook: {
475 | name: 'facebook',
476 | url: '/auth/facebook',
477 | authorizationEndpoint: 'https://www.facebook.com/v2.5/dialog/oauth',
478 | redirectUri: window.location.origin + '/',
479 | requiredUrlParams: ['display', 'scope'],
480 | scope: ['email'],
481 | scopeDelimiter: ',',
482 | display: 'popup',
483 | oauthType: '2.0',
484 | popupOptions: { width: 580, height: 400 }
485 | },
486 |
487 | google: {
488 | name: 'google',
489 | url: '/auth/google',
490 | authorizationEndpoint: 'https://accounts.google.com/o/oauth2/auth',
491 | redirectUri: window.location.origin,
492 | requiredUrlParams: ['scope'],
493 | optionalUrlParams: ['display'],
494 | scope: ['profile', 'email'],
495 | scopePrefix: 'openid',
496 | scopeDelimiter: ' ',
497 | display: 'popup',
498 | oauthType: '2.0',
499 | popupOptions: { width: 452, height: 633 }
500 | },
501 |
502 | github: {
503 | name: 'github',
504 | url: '/auth/github',
505 | authorizationEndpoint: 'https://github.com/login/oauth/authorize',
506 | redirectUri: window.location.origin,
507 | optionalUrlParams: ['scope'],
508 | scope: ['user:email'],
509 | scopeDelimiter: ' ',
510 | oauthType: '2.0',
511 | popupOptions: { width: 1020, height: 618 }
512 | },
513 |
514 | instagram: {
515 | name: 'instagram',
516 | url: '/auth/instagram',
517 | authorizationEndpoint: 'https://api.instagram.com/oauth/authorize',
518 | redirectUri: window.location.origin,
519 | requiredUrlParams: ['scope'],
520 | scope: ['basic'],
521 | scopeDelimiter: '+',
522 | oauthType: '2.0',
523 | popupOptions: { width: null, height: null }
524 | },
525 |
526 | twitter: {
527 | name: 'twitter',
528 | url: '/auth/twitter',
529 | authorizationEndpoint: 'https://api.twitter.com/oauth/authenticate',
530 | redirectUri: window.location.origin,
531 | oauthType: '1.0',
532 | popupOptions: { width: 495, height: 645 }
533 | },
534 |
535 | bitbucket: {
536 | name: 'bitbucket',
537 | url: '/auth/bitbucket',
538 | authorizationEndpoint: 'https://bitbucket.org/site/oauth2/authorize',
539 | redirectUri: window.location.origin + '/',
540 | optionalUrlParams: ['scope'],
541 | scope: ['email'],
542 | scopeDelimiter: ' ',
543 | oauthType: '2.0',
544 | popupOptions: { width: 1020, height: 618 }
545 | },
546 |
547 | linkedin: {
548 | name: 'linkedin',
549 | url: '/auth/linkedin',
550 | authorizationEndpoint: 'https://www.linkedin.com/oauth/v2/authorization',
551 | redirectUri: window.location.origin,
552 | requiredUrlParams: ['state','scope'],
553 | scope: ['r_liteprofile','r_emailaddress'],
554 | scopeDelimiter: ' ',
555 | state: 'STATE',
556 | oauthType: '2.0',
557 | popupOptions: { width: 527, height: 582 }
558 | },
559 |
560 | vkontakte: {
561 | name: 'vkontakte',
562 | url: '/auth/vkontakte',
563 | authorizationEndpoint: 'https://oauth.vk.com/authorize',
564 | redirectUri: window.location.origin + '/',
565 | requiredUrlParams: ['scope'],
566 | scope: ['email'],
567 | scopeDelimiter: ',',
568 | display: 'popup',
569 | oauthType: '2.0',
570 | popupOptions: { width: 580, height: 400 }
571 | },
572 |
573 | live: {
574 | name: 'live',
575 | url: '/auth/live',
576 | authorizationEndpoint: 'https://login.live.com/oauth20_authorize.srf',
577 | redirectUri: window.location.origin,
578 | requiredUrlParams: ['display', 'scope'],
579 | scope: ['wl.emails'],
580 | scopeDelimiter: ' ',
581 | display: 'popup',
582 | oauthType: '2.0',
583 | popupOptions: { width: 500, height: 560 }
584 | },
585 |
586 | oauth1: {
587 | name: null,
588 | url: '/auth/oauth1',
589 | authorizationEndpoint: null,
590 | redirectUri: window.location.origin,
591 | oauthType: '1.0',
592 | popupOptions: null
593 | },
594 |
595 | oauth2: {
596 | name: null,
597 | url: '/auth/oauth2',
598 | clientId: null,
599 | redirectUri: window.location.origin,
600 | authorizationEndpoint: null,
601 | defaultUrlParams: ['response_type', 'client_id', 'redirect_uri'],
602 | requiredUrlParams: null,
603 | optionalUrlParams: null,
604 | scope: null,
605 | scopePrefix: null,
606 | scopeDelimiter: null,
607 | state: null,
608 | oauthType: '2.0',
609 | popupOptions: null,
610 | responseType: 'code',
611 | responseParams: {
612 | code: 'code',
613 | clientId: 'clientId',
614 | redirectUri: 'redirectUri'
615 | }
616 | }
617 | }
618 | };
619 |
620 | var CookieStorage = function CookieStorage(defaultOptions) {
621 | this._defaultOptions = objectExtend({
622 | domain: window.location.hostname,
623 | expires: null,
624 | path: '/',
625 | secure: false
626 | }, defaultOptions);
627 | };
628 |
629 | CookieStorage.prototype.setItem = function setItem (key, value) {
630 | var options = objectExtend({}, this._defaultOptions);
631 | var cookie = formatCookie(key, value, options);
632 | this._setCookie(cookie);
633 | };
634 |
635 | CookieStorage.prototype.getItem = function getItem (key) {
636 | var cookies = parseCookies(this._getCookie());
637 | return cookies.hasOwnProperty(key) ? cookies[key] : null;
638 | };
639 |
640 | CookieStorage.prototype.removeItem = function removeItem (key) {
641 | var value = '';
642 | var defaultOptions = objectExtend({}, this._defaultOptions);
643 | var options = objectExtend(defaultOptions, {
644 | expires: new Date(0)
645 | });
646 | var cookie = formatCookie(key, value, options);
647 | this._setCookie(cookie);
648 | };
649 |
650 | CookieStorage.prototype._getCookie = function _getCookie () {
651 | return typeof document === 'undefined'
652 | ? '' : typeof document.cookie === 'undefined'
653 | ? '' : document.cookie;
654 | };
655 |
656 | CookieStorage.prototype._setCookie = function _setCookie (cookie) {
657 | document.cookie = cookie;
658 | };
659 |
660 | var LocalStorage = function LocalStorage(namespace) {
661 | this.namespace = namespace || null;
662 | };
663 |
664 | LocalStorage.prototype.setItem = function setItem (key, value) {
665 | window.localStorage.setItem(this._getStorageKey(key), value);
666 | };
667 |
668 | LocalStorage.prototype.getItem = function getItem (key) {
669 | return window.localStorage.getItem(this._getStorageKey(key))
670 | };
671 |
672 | LocalStorage.prototype.removeItem = function removeItem (key) {
673 | window.localStorage.removeItem(this._getStorageKey(key));
674 | };
675 |
676 | LocalStorage.prototype._getStorageKey = function _getStorageKey (key) {
677 | if (this.namespace) {
678 | return [this.namespace, key].join('.')
679 | }
680 | return key;
681 | };
682 |
683 | var MemoryStorage = function MemoryStorage(namespace) {
684 | this.namespace = namespace || null;
685 | this._storage = {};
686 | };
687 |
688 | MemoryStorage.prototype.setItem = function setItem (key, value) {
689 | this._storage[this._getStorageKey(key)] = value;
690 | };
691 |
692 | MemoryStorage.prototype.getItem = function getItem (key) {
693 | return this._storage[this._getStorageKey(key)]
694 | };
695 |
696 | MemoryStorage.prototype.removeItem = function removeItem (key) {
697 | delete this._storage[this._getStorageKey(key)];
698 | };
699 |
700 | MemoryStorage.prototype._getStorageKey = function _getStorageKey (key) {
701 | if (this.namespace) {
702 | return [this.namespace, key].join('.')
703 | }
704 | return key;
705 | };
706 |
707 | var LocalStorage$2 = function LocalStorage(namespace) {
708 | this.namespace = namespace || null;
709 | };
710 |
711 | LocalStorage$2.prototype.setItem = function setItem (key, value) {
712 | window.sessionStorage.setItem(this._getStorageKey(key), value);
713 | };
714 |
715 | LocalStorage$2.prototype.getItem = function getItem (key) {
716 | return window.sessionStorage.getItem(this._getStorageKey(key))
717 | };
718 |
719 | LocalStorage$2.prototype.removeItem = function removeItem (key) {
720 | window.sessionStorage.removeItem(this._getStorageKey(key));
721 | };
722 |
723 | LocalStorage$2.prototype._getStorageKey = function _getStorageKey (key) {
724 | if (this.namespace) {
725 | return [this.namespace, key].join('.')
726 | }
727 | return key;
728 | };
729 |
730 | function StorageFactory(options) {
731 | switch (options.storageType) {
732 | case 'localStorage':
733 | try {
734 | window.localStorage.setItem('testKey', 'test');
735 | window.localStorage.removeItem('testKey');
736 | return new LocalStorage(options.storageNamespace)
737 | } catch(e) {}
738 |
739 | case 'sessionStorage':
740 | try {
741 | window.sessionStorage.setItem('testKey', 'test');
742 | window.sessionStorage.removeItem('testKey');
743 | return new LocalStorage$2(options.storageNamespace)
744 | } catch (e) {}
745 |
746 | case 'cookieStorage':
747 | return new CookieStorage(options.cookieStorage);
748 |
749 | case 'memoryStorage':
750 | default:
751 | return new MemoryStorage(options.storageNamespace)
752 | break;
753 | }
754 | }
755 |
756 | /**
757 | * OAuth2 popup management class
758 | *
759 | * @author Sahat Yalkabov
760 | * @copyright Class mostly taken from https://github.com/sahat/satellizer
761 | * and adjusted to fit vue-social-auth library
762 | */
763 | var OAuthPopup = function OAuthPopup(url, name, popupOptions) {
764 | this.popup = null;
765 | this.url = url;
766 | this.name = name;
767 | this.popupOptions = popupOptions;
768 | };
769 |
770 | OAuthPopup.prototype.open = function open (redirectUri, skipPooling) {
771 | try {
772 | this.popup = window.open(this.url, this.name, this._stringifyOptions());
773 | if (this.popup && this.popup.focus) {
774 | this.popup.focus();
775 | }
776 |
777 | if (skipPooling) {
778 | return Promise$1.resolve()
779 | } else {
780 | return this.pooling(redirectUri)
781 | }
782 | } catch(e) {
783 | return Promise$1.reject(new Error('OAuth popup error occurred'))
784 | }
785 | };
786 |
787 | OAuthPopup.prototype.pooling = function pooling (redirectUri) {
788 | var this$1 = this;
789 |
790 | return new Promise$1(function (resolve, reject) {
791 | var redirectUriParser = document.createElement('a');
792 | redirectUriParser.href = redirectUri;
793 | var redirectUriPath = getFullUrlPath(redirectUriParser);
794 |
795 | var poolingInterval = setInterval(function () {
796 | if (!this$1.popup || this$1.popup.closed || this$1.popup.closed === undefined) {
797 | clearInterval(poolingInterval);
798 | poolingInterval = null;
799 | reject(new Error('Auth popup window closed'));
800 | }
801 |
802 | try {
803 | var popupWindowPath = getFullUrlPath(this$1.popup.location);
804 |
805 | if (popupWindowPath === redirectUriPath) {
806 | if (this$1.popup.location.search || this$1.popup.location.hash) {
807 | var query = parseQueryString(this$1.popup.location.search.substring(1).replace(/\/$/, ''));
808 | var hash = parseQueryString(this$1.popup.location.hash.substring(1).replace(/[\/$]/, ''));
809 | var params = objectExtend({}, query);
810 | params = objectExtend(params, hash);
811 |
812 | if (params.error) {
813 | reject(new Error(params.error));
814 | } else {
815 | resolve(params);
816 | }
817 | } else {
818 | reject(new Error('OAuth redirect has occurred but no query or hash parameters were found.'));
819 | }
820 |
821 | clearInterval(poolingInterval);
822 | poolingInterval = null;
823 | this$1.popup.close();
824 | }
825 | } catch(e) {
826 | // Ignore DOMException: Blocked a frame with origin from accessing a cross-origin frame.
827 | }
828 | }, 250);
829 | })
830 | };
831 |
832 | OAuthPopup.prototype._stringifyOptions = function _stringifyOptions () {
833 | var this$1 = this;
834 |
835 | var options = [];
836 | for (var optionKey in this$1.popupOptions) {
837 | if (!isUndefined(this$1.popupOptions[optionKey])) {
838 | options.push((optionKey + "=" + (this$1.popupOptions[optionKey])));
839 | }
840 | }
841 | return options.join(',')
842 | };
843 |
844 | var defaultProviderConfig = {
845 | name: null,
846 | url: null,
847 | authorizationEndpoint: null,
848 | scope: null,
849 | scopePrefix: null,
850 | scopeDelimiter: null,
851 | redirectUri: null,
852 | requiredUrlParams: null,
853 | defaultUrlParams: null,
854 | oauthType: '1.0',
855 | popupOptions: {}
856 | };
857 |
858 | var OAuth = function OAuth($http, storage, providerConfig, options) {
859 | this.$http = $http;
860 | this.storage = storage;
861 | this.providerConfig = objectExtend({}, defaultProviderConfig);
862 | this.providerConfig = objectExtend(this.providerConfig, providerConfig);
863 | this.options = options;
864 | };
865 |
866 | /**
867 | * Initialize OAuth1 process
868 | * @param{Object} userData User data
869 | * @return {Promise}
870 | */
871 | OAuth.prototype.init = function init (userData) {
872 | var this$1 = this;
873 |
874 | this.oauthPopup = new OAuthPopup('about:blank', this.providerConfig.name, this.providerConfig.popupOptions);
875 |
876 | if (window && !window['cordova']) {
877 | this.oauthPopup.open(this.providerConfig.redirectUri, true);
878 | }
879 |
880 | return this.getRequestToken().then(function (response) {
881 | return this$1.openPopup(response).then(function (popupResponse) {
882 | return this$1.exchangeForToken(popupResponse, userData)
883 | })
884 | })
885 | };
886 |
887 | /**
888 | * Get OAuth1 request token
889 | * @return {Promise}
890 | */
891 | OAuth.prototype.getRequestToken = function getRequestToken () {
892 | var requestOptions = {};
893 | requestOptions.method = 'POST';
894 | requestOptions[this.options.requestDataKey] = objectExtend({}, this.providerConfig);
895 | requestOptions.withCredentials = this.options.withCredentials;
896 | if (this.options.baseUrl) {
897 | requestOptions.url = joinUrl(this.options.baseUrl, this.providerConfig.url);
898 | } else {
899 | requestOptions.url = this.providerConfig.url;
900 | }
901 |
902 | return this.$http(requestOptions)
903 | };
904 |
905 | /**
906 | * Open OAuth1 popup
907 | * @param{Object} response Response object containing request token
908 | * @return {Promise}
909 | */
910 | OAuth.prototype.openPopup = function openPopup (response) {
911 | var url = [this.providerConfig.authorizationEndpoint, this.buildQueryString(response[this.options.responseDataKey])].join('?');
912 |
913 | this.oauthPopup.popup.location = url;
914 | if (window && window['cordova']) {
915 | return this.oauthPopup.open(this.providerConfig.redirectUri)
916 | } else {
917 | return this.oauthPopup.pooling(this.providerConfig.redirectUri)
918 | }
919 | };
920 |
921 | /**
922 | * Exchange token and token verifier for access token
923 | * @param{Object} oauth OAuth data containing token and token verifier
924 | * @param{Object} userData User data
925 | * @return {Promise}
926 | */
927 | OAuth.prototype.exchangeForToken = function exchangeForToken (oauth, userData) {
928 | var payload = objectExtend({}, userData);
929 | payload = objectExtend(payload, oauth);
930 | var requestOptions = {};
931 | requestOptions.method = 'POST';
932 | requestOptions[this.options.requestDataKey] = payload;
933 | requestOptions.withCredentials = this.options.withCredentials;
934 | if (this.options.baseUrl) {
935 | requestOptions.url = joinUrl(this.options.baseUrl, this.providerConfig.url);
936 | } else {
937 | requestOptions.url = this.providerConfig.url;
938 | }
939 | return this.$http(requestOptions)
940 | };
941 |
942 | OAuth.prototype.buildQueryString = function buildQueryString (params) {
943 | var parsedParams = [];
944 | for (var key in params) {
945 | var value = params[key];
946 | parsedParams.push(encodeURIComponent(key) + '=' + encodeURIComponent(value));
947 | }
948 | return parsedParams.join('&');
949 | };
950 |
951 | /**
952 | * Default provider configuration
953 | * @type {Object}
954 | */
955 | var defaultProviderConfig$1 = {
956 | name: null,
957 | url: null,
958 | clientId: null,
959 | authorizationEndpoint: null,
960 | redirectUri: null,
961 | scope: null,
962 | scopePrefix: null,
963 | scopeDelimiter: null,
964 | state: null,
965 | requiredUrlParams: null,
966 | defaultUrlParams: ['response_type', 'client_id', 'redirect_uri'],
967 | responseType: 'code',
968 | responseParams: {
969 | code: 'code',
970 | clientId: 'clientId',
971 | redirectUri: 'redirectUri'
972 | },
973 | oauthType: '2.0',
974 | popupOptions: {}
975 | };
976 |
977 | var OAuth2 = function OAuth2($http, storage, providerConfig, options) {
978 | this.$http = $http;
979 | this.storage = storage;
980 | this.providerConfig = objectExtend({}, defaultProviderConfig$1);
981 | this.providerConfig = objectExtend(this.providerConfig, providerConfig);
982 | this.options = options;
983 | };
984 |
985 | OAuth2.prototype.init = function init (userData) {
986 | var this$1 = this;
987 |
988 | var stateName = this.providerConfig.name + '_state';
989 | if (isFunction(this.providerConfig.state)) {
990 | this.storage.setItem(stateName, this.providerConfig.state());
991 | } else if (isString(this.providerConfig.state)) {
992 | this.storage.setItem(stateName, this.providerConfig.state);
993 | }
994 |
995 | var url = [this.providerConfig.authorizationEndpoint, this._stringifyRequestParams()].join('?');
996 |
997 | this.oauthPopup = new OAuthPopup(url, this.providerConfig.name, this.providerConfig.popupOptions);
998 |
999 | return new Promise(function (resolve, reject) {
1000 | this$1.oauthPopup.open(this$1.providerConfig.redirectUri).then(function (response) {
1001 | if (this$1.providerConfig.responseType === 'code' || !this$1.providerConfig.url) {
1002 | return resolve(response)
1003 | }
1004 |
1005 | if (response.state && response.state !== this$1.storage.getItem(stateName)) {
1006 | return reject(new Error('State parameter value does not match original OAuth request state value'))
1007 | }
1008 |
1009 | resolve(this$1.exchangeForToken(response, userData));
1010 | }).catch(function (err) {
1011 | reject(err);
1012 | });
1013 | })
1014 | };
1015 |
1016 | /**
1017 | * Exchange temporary oauth data for access token
1018 | * @author Sahat Yalkabov
1019 | * @copyright Method taken from https://github.com/sahat/satellizer
1020 | *
1021 | * @param{[type]} oauth [description]
1022 | * @param{[type]} userData [description]
1023 | * @return {[type]} [description]
1024 | */
1025 | OAuth2.prototype.exchangeForToken = function exchangeForToken (oauth, userData) {
1026 | var this$1 = this;
1027 |
1028 | var payload = objectExtend({}, userData);
1029 |
1030 | for (var key in defaultProviderConfig$1.responseParams) {
1031 | var value = defaultProviderConfig$1[key];
1032 |
1033 | switch(key) {
1034 | case 'code':
1035 | payload[key] = oauth.code;
1036 | break
1037 | case 'clientId':
1038 | payload[key] = this$1.providerConfig.clientId;
1039 | break
1040 | case 'redirectUri':
1041 | payload[key] = this$1.providerConfig.redirectUri;
1042 | break
1043 | default:
1044 | payload[key] = oauth[key];
1045 | }
1046 | }
1047 |
1048 | if (oauth.state) {
1049 | payload.state = oauth.state;
1050 | }
1051 |
1052 | var exchangeTokenUrl;
1053 | if (this.options.baseUrl) {
1054 | exchangeTokenUrl = joinUrl(this.options.baseUrl, this.providerConfig.url);
1055 | } else {
1056 | exchangeTokenUrl = this.providerConfig.url;
1057 | }
1058 |
1059 | return this.$http.post(exchangeTokenUrl, payload, {
1060 | withCredentials: this.options.withCredentials
1061 | })
1062 | };
1063 |
1064 | /**
1065 | * Stringify oauth params
1066 | * @author Sahat Yalkabov
1067 | * @copyright Method taken from https://github.com/sahat/satellizer
1068 | *
1069 | * @return {String}
1070 | */
1071 | OAuth2.prototype._stringifyRequestParams = function _stringifyRequestParams () {
1072 | var this$1 = this;
1073 |
1074 | var keyValuePairs = [];
1075 | var paramCategories = ['defaultUrlParams', 'requiredUrlParams', 'optionalUrlParams'];
1076 |
1077 | paramCategories.forEach(function (categoryName) {
1078 | if (!this$1.providerConfig[categoryName]) { return }
1079 | if (!Array.isArray(this$1.providerConfig[categoryName])) { return }
1080 |
1081 | this$1.providerConfig[categoryName].forEach(function (paramName) {
1082 | var camelCaseParamName = camelCase(paramName);
1083 | var paramValue = isFunction(this$1.providerConfig[paramName]) ? this$1.providerConfig[paramName]() : this$1.providerConfig[camelCaseParamName];
1084 |
1085 | if (paramName === 'redirect_uri' && !paramValue) { return }
1086 |
1087 | if (paramName === 'state') {
1088 | var stateName = this$1.providerConfig.name + '_state';
1089 | paramValue = encodeURIComponent(this$1.storage.getItem(stateName));
1090 | }
1091 | if (paramName === 'scope' && Array.isArray(paramValue)) {
1092 | paramValue = paramValue.join(this$1.providerConfig.scopeDelimiter);
1093 | if (this$1.providerConfig.scopePrefix) {
1094 | paramValue = [this$1.providerConfig.scopePrefix, paramValue].join(this$1.providerConfig.scopeDelimiter);
1095 | }
1096 | }
1097 |
1098 | keyValuePairs.push([paramName, paramValue]);
1099 | });
1100 | });
1101 |
1102 | return keyValuePairs.map(function (param) {
1103 | return param.join('=')
1104 | }).join('&')
1105 | };
1106 |
1107 | var VueSocialauth = function VueSocialauth($http, overrideOptions) {
1108 | var options = objectExtend({}, defaultOptions);
1109 | options = objectExtend(options, overrideOptions);
1110 | var storage = StorageFactory(options);
1111 |
1112 | Object.defineProperties(this, {
1113 | $http: {
1114 | get: function get() {
1115 | return $http
1116 | }
1117 | },
1118 |
1119 | options: {
1120 | get: function get() {
1121 | return options
1122 | }
1123 | },
1124 |
1125 | storage: {
1126 | get: function get() {
1127 | return storage
1128 | }
1129 | },
1130 |
1131 | tokenName: {
1132 | get: function get() {
1133 | if (this.options.tokenPrefix) {
1134 | return [this.options.tokenPrefix, this.options.tokenName].join('_')
1135 | } else {
1136 | return this.options.tokenName
1137 | }
1138 | }
1139 | }
1140 | });
1141 |
1142 | // Setup request interceptors
1143 | if (this.options.bindRequestInterceptor && isFunction(this.options.bindRequestInterceptor) &&
1144 | this.options.bindResponseInterceptor && isFunction(this.options.bindResponseInterceptor)) {
1145 |
1146 | this.options.bindRequestInterceptor.call(this, this);
1147 | this.options.bindResponseInterceptor.call(this, this);
1148 | } else {
1149 | throw new Error('Both request and response interceptors must be functions')
1150 | }
1151 | };
1152 |
1153 | /**
1154 | * Check if user is authenticated
1155 | * @author Sahat Yalkabov
1156 | * @copyright Method taken from https://github.com/sahat/satellizer
1157 | * @return {Boolean}
1158 | */
1159 | // isAuthenticated() {
1160 | // let token = this.storage.getItem(this.tokenName)
1161 |
1162 | // if (token) {// Token is present
1163 | // if (token.split('.').length === 3) {// Token with a valid JWT format XXX.YYY.ZZZ
1164 | // try { // Could be a valid JWT or an access token with the same format
1165 | // const base64Url = token.split('.')[1];
1166 | // const base64 = base64Url.replace('-', '+').replace('_', '/');
1167 | // const exp = JSON.parse(window.atob(base64)).exp;
1168 | // if (typeof exp === 'number') {// JWT with an optonal expiration claims
1169 | // return Math.round(new Date().getTime() / 1000) < exp;
1170 | // }
1171 | // } catch (e) {
1172 | // return true;// Pass: Non-JWT token that looks like JWT
1173 | // }
1174 | // }
1175 | // return true;// Pass: All other tokens
1176 | // }
1177 | // return false
1178 | // }
1179 |
1180 | /**
1181 | * Get token if user is authenticated
1182 | * @return {String} Authentication token
1183 | */
1184 | VueSocialauth.prototype.getToken = function getToken () {
1185 | return this.storage.getItem(this.tokenName)
1186 | };
1187 |
1188 | /**
1189 | * Set new authentication token
1190 | * @param {String|Object} token
1191 | */
1192 | // setToken(response) {
1193 | // if (response[this.options.responseDataKey]) {
1194 | // response = response[this.options.responseDataKey];
1195 | // }
1196 |
1197 | // let token;
1198 | // if (response.access_token) {
1199 | // if (isObject(response.access_token) && isObject(response.access_token[this.options.responseDataKey])) {
1200 | // response = response.access_token
1201 | // } else if (isString(response.access_token)) {
1202 | // token = response.access_token
1203 | // }
1204 | // }
1205 |
1206 | // if (!token && response) {
1207 | // token = response[this.options.tokenName]
1208 | // }
1209 |
1210 | // if (token) {
1211 | // this.storage.setItem(this.tokenName, token)
1212 | // }
1213 | // }
1214 |
1215 | // getPayload() {
1216 | // const token = this.storage.getItem(this.tokenName);
1217 |
1218 | // if (token && token.split('.').length === 3) {
1219 | // try {
1220 | // const base64Url = token.split('.')[1];
1221 | // const base64 = base64Url.replace('-', '+').replace('_', '/');
1222 | // return JSON.parse(decodeBase64(base64));
1223 | // } catch (e) {}
1224 | // }
1225 | // }
1226 |
1227 | /**
1228 | * Login user using email and password
1229 | * @param{Object} user User data
1230 | * @param{Object} requestOptions Request options
1231 | * @return {Promise} Request promise
1232 | */
1233 | // login(user, requestOptions) {
1234 | // requestOptions = requestOptions || {}
1235 | // requestOptions.url = requestOptions.url ? requestOptions.url : joinUrl(this.options.baseUrl, this.options.loginUrl)
1236 | // requestOptions[this.options.requestDataKey] = user || requestOptions[this.options.requestDataKey]
1237 | // requestOptions.method = requestOptions.method || 'POST'
1238 | // requestOptions.withCredentials = requestOptions.withCredentials || this.options.withCredentials
1239 |
1240 | // return this.$http(requestOptions).then((response) => {
1241 | // this.setToken(response)
1242 | // return response
1243 | // })
1244 | // }
1245 |
1246 | /**
1247 | * Register new user
1248 | * @param{Object} user User data
1249 | * @param{Object} requestOptions Request options
1250 | * @return {Promise} Request promise
1251 | */
1252 | // register(user, requestOptions) {
1253 | // requestOptions = requestOptions || {}
1254 | // requestOptions.url = requestOptions.url ? requestOptions.url : joinUrl(this.options.baseUrl, this.options.registerUrl)
1255 | // requestOptions[this.options.requestDataKey] = user || requestOptions[this.options.requestDataKey]
1256 | // requestOptions.method = requestOptions.method || 'POST'
1257 | // requestOptions.withCredentials = requestOptions.withCredentials || this.options.withCredentials
1258 |
1259 | // return this.$http(requestOptions).then((response) => {
1260 | // this.setToken(response)
1261 | // return response
1262 | // })
1263 | // }
1264 |
1265 | /**
1266 | * Logout current user
1267 | * @param{Object} requestOptionsLogout request options object
1268 | * @return {Promise} Request promise
1269 | */
1270 | // logout(requestOptions) {
1271 | // if (!this.isAuthenticated()) {
1272 | // return Promise.reject(new Error('There is no currently authenticated user'))
1273 | // }
1274 |
1275 | // requestOptions = requestOptions || {}
1276 | // requestOptions.url = requestOptions.logoutUrl || this.options.logoutUrl
1277 |
1278 | // if (requestOptions.url) {
1279 | // requestOptions.method = requestOptions.method || 'POST'
1280 | // requestOptions.withCredentials = requestOptions.withCredentials || this.options.withCredentials
1281 |
1282 | // return this.$http(requestOptions).then((response) => {
1283 | // this.storage.removeItem(this.tokenName)
1284 | // })
1285 | // } else {
1286 | // this.storage.removeItem(this.tokenName)
1287 | // return Promise.resolve();
1288 | // }
1289 | // }
1290 |
1291 | /**
1292 | * Authenticate user using authentication provider
1293 | *
1294 | * @param{String} provider Provider name
1295 | * @param{Object} userData User data
1296 | * @param{Object} requestOptions Request options
1297 | * @return {Promise} Request promise
1298 | */
1299 | VueSocialauth.prototype.authenticate = function authenticate (provider, userData, requestOptions) {
1300 | var this$1 = this;
1301 |
1302 | return new Promise$1(function (resolve, reject) {
1303 | var providerConfig = this$1.options.providers[provider];
1304 | if (!providerConfig) {
1305 | return reject(new Error('Unknown provider'))
1306 | }
1307 |
1308 | var providerInstance;
1309 | switch (providerConfig.oauthType) {
1310 | case '1.0':
1311 | providerInstance = new OAuth(this$1.$http, this$1.storage, providerConfig, this$1.options);
1312 | break
1313 | case '2.0':
1314 | providerInstance = new OAuth2(this$1.$http, this$1.storage, providerConfig, this$1.options);
1315 | break
1316 | default:
1317 | return reject(new Error('Invalid OAuth type'))
1318 | break
1319 | }
1320 |
1321 | return providerInstance.init(userData).then(function (response) {
1322 | return resolve(response)
1323 |
1324 | }).catch(function (err) { return reject(err); })
1325 | })
1326 | };
1327 |
1328 | /**
1329 | * VueSocialauth plugin
1330 | * @param {Object} Vue
1331 | * @param {Object} options
1332 | */
1333 | function plugin(Vue, options) {
1334 | if (plugin.installed) {
1335 | return
1336 | }
1337 | plugin.installed = true;
1338 |
1339 | var property = options.property || '$auth';
1340 |
1341 | var vueAuthInstance = null;
1342 | Object.defineProperties(Vue.prototype, ( obj = {}, obj[property] = {
1343 | get: function get() {
1344 | if (!vueAuthInstance) {
1345 | // Request handler library not found, throw error
1346 | // verified vue or nuxt instance
1347 | if (this.$axios) {
1348 | vueAuthInstance = new VueSocialauth(this.$axios, options);
1349 | } else if (this.$http) {
1350 | vueAuthInstance = new VueSocialauth(this.$http, options);
1351 | } else {
1352 | throw new Error('Request handler instance not found')
1353 | }
1354 | }
1355 | return vueAuthInstance
1356 | }
1357 | }, obj ));
1358 | var obj;
1359 | }
1360 |
1361 | /**
1362 | * External factory helper for ES5 and CommonJS
1363 | * @param {Object} $http Instance of request handling library
1364 | * @param {Object} options Configuration object
1365 | * @return {VueSocialauth} VueSocialauth instance
1366 | */
1367 | plugin.factory = function ($http, options) {
1368 | return new VueSocialauth($http, options)
1369 | };
1370 |
1371 | return plugin;
1372 |
1373 | })));
1374 |
--------------------------------------------------------------------------------
/dist/vue-social-auth.min.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * vue-social-auth v0.0.1
3 | * https://github.com/diadal/vue-social-auth
4 | * Released under the MIT License.
5 | */
6 |
7 | !function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):t.VueSocialauth=e()}(this,function(){"use strict";function t(t){return t.replace(/([\:\-\_]+(.))/g,function(t,e,o,n){return n?o.toUpperCase():o})}function e(t){return void 0===t}function o(t){return"string"==typeof t}function n(t){return"function"==typeof t}function i(t,e){return null==t||null==e?t:(Object.keys(e).forEach(function(o){"[object Object]"==Object.prototype.toString.call(e[o])?"[object Object]"!=Object.prototype.toString.call(t[o])?t[o]=e[o]:t[o]=i(t[o],e[o]):t[o]=e[o]}),t)}function r(t,e){if(/^(?:[a-z]+:)?\/\//i.test(e))return e;var o=[t,e].join("/");return function(t){return t.replace(/[\/]+/g,"/").replace(/\/\?/g,"?").replace(/\/\#/g,"#").replace(/\:\//g,"://")}(o)}function a(t){var e="https:"===t.protocol;return t.protocol+"//"+t.hostname+":"+(t.port||(e?"443":"80"))+(/^\//.test(t.pathname)?t.pathname:"/"+t.pathname)}function s(t){var e,o,n={};return(t||"").split("&").forEach(function(t){t&&(o=t.split("="),e=decodeURIComponent(o[0]),n[e]=!o[1]||decodeURIComponent(o[1]))}),n}function p(t){if(0===t.length)return{};var e={},o=new RegExp("\\s*;\\s*");return t.split(o).forEach(function(t){var o=t.split("="),n=o[0],i=o[1],r=decodeURIComponent(n),a=decodeURIComponent(i);e[r]=a}),e}function u(t){var e=t.path,o=t.domain,n=t.expires,i=t.secure;return[void 0===e||null===e?"":";path="+e,void 0===o||null===o?"":";domain="+o,void 0===n||null===n?"":";expires="+n.toUTCString(),void 0===i||null===i||!1===i?"":";secure"].join("")}function c(t,e,o){return[encodeURIComponent(t),"=",encodeURIComponent(e),u(o)].join("")}function l(){}function h(t,e){return function(){t.apply(e,arguments)}}function d(t){if("object"!=typeof this)throw new TypeError("Promises must be constructed via new");if("function"!=typeof t)throw new TypeError("not a function");this._state=0,this._handled=!1,this._value=void 0,this._deferreds=[],w(t,this)}function f(t,e){for(;3===t._state;)t=t._value;if(0===t._state)return void t._deferreds.push(e);t._handled=!0,d._immediateFn(function(){var o=1===t._state?e.onFulfilled:e.onRejected;if(null===o)return void(1===t._state?g:m)(e.promise,t._value);var n;try{n=o(t._value)}catch(t){return void m(e.promise,t)}g(e.promise,n)})}function g(t,e){try{if(e===t)throw new TypeError("A promise cannot be resolved with itself.");if(e&&("object"==typeof e||"function"==typeof e)){var o=e.then;if(e instanceof d)return t._state=3,t._value=e,void v(t);if("function"==typeof o)return void w(h(o,e),t)}t._state=1,t._value=e,v(t)}catch(e){m(t,e)}}function m(t,e){t._state=2,t._value=e,v(t)}function v(t){2===t._state&&0===t._deferreds.length&&d._immediateFn(function(){t._handled||d._unhandledRejectionFn(t._value)});for(var e=0,o=t._deferreds.length;e {
5 | // aviable only in client side
6 | if (!process.client) {
7 | return
8 | }
9 |
10 | //initialize plugin with options
11 | const pluginOptions = [<%= serialize(options) %>][0] || {}
12 | Vue.use(VueSocialAuth, pluginOptions)
13 | }
14 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "vue-social-auth-5",
3 | "version": "0.0.1",
4 | "description": "Social Authentication library for laravel with Vue.js (SPA)",
5 | "main": "dist/vue-social-auth.js",
6 | "module": "dist/vue-social-auth.es2017.js",
7 | "unpkg": "dist/vue-social-auth.js",
8 | "scripts": {
9 | "build": "node build/build.js"
10 | },
11 | "keywords": [
12 | "vue",
13 | "vuejs",
14 | "auth",
15 | "laravel vue",
16 | "vue Social Login",
17 | "vue facebook",
18 | "vue google",
19 | "vue github",
20 | "vue vkontakte"
21 | ],
22 | "author": {
23 | "name": "diadal",
24 | "email": "info@diadal.com.ng",
25 | "url": "https://diadal.com.ng"
26 | },
27 | "repository": {
28 | "type": "git",
29 | "url": "https://github.com/diadal/vue-social-auth.git"
30 | },
31 | "license": "MIT",
32 | "devDependencies": {
33 | "axios": "^0.21.1",
34 | "body-parser": "^1.17.1",
35 | "connect-history-api-fallback": "^1.3.0",
36 | "cors": "^2.8.1",
37 | "express": "^4.15.2",
38 | "gulp": "^4.0.0",
39 | "gulp-connect": "^5.0.0",
40 | "node-dev": "^3.1.3",
41 | "oauth": "^0.9.15",
42 | "oauth-signature": "^1.3.1",
43 | "parallelshell": "^2.0.0",
44 | "request": "^2.81.0",
45 | "rollup": "^0.41.6",
46 | "rollup-plugin-babel": "^2.7.1",
47 | "rollup-plugin-buble": "^0.15.0",
48 | "rollup-plugin-commonjs": "^8.0.2",
49 | "rollup-plugin-node-resolve": "^3.0.0",
50 | "rollup-plugin-uglify": "^1.0.1",
51 | "rollup-stream": "^1.19.0",
52 | "uglify-js": "^2.8.22",
53 | "unix-timestamp": "^0.2.0",
54 | "vinyl-source-stream": "^1.1.0",
55 | "vue": "^2.5.2",
56 | "vue-axios": "^2.0.2",
57 | "vue-router": "^2.3.0",
58 | "vuex": "^2.2.1",
59 | "webpack": "^5.23.0"
60 | },
61 | "tags": [
62 | "auth",
63 | "authentication",
64 | "login",
65 | "registration",
66 | "jwt",
67 | "token",
68 | "vuejs",
69 | "vue.js",
70 | "github",
71 | "facebook",
72 | "google",
73 | "twitter",
74 | "oauth",
75 | "oauth 1.0",
76 | "oauth 2.0",
77 | "laravel",
78 | "SPA Social Login"
79 | ],
80 | "dependencies": {
81 | "graceful-fs": "^4.1.15"
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/src/authenticate.js:
--------------------------------------------------------------------------------
1 | import Promise from './promise.js'
2 | import { objectExtend, isString, isObject, isFunction, joinUrl, decodeBase64 } from './utils.js'
3 | import defaultOptions from './options.js'
4 | import StorageFactory from './storage.js'
5 | import OAuth1 from './oauth/oauth1.js'
6 | import OAuth2 from './oauth/oauth2.js'
7 |
8 | export default class VueSocialauth {
9 | constructor($http, overrideOptions) {
10 | let options = objectExtend({}, defaultOptions)
11 | options = objectExtend(options, overrideOptions)
12 | let storage = StorageFactory(options)
13 |
14 | Object.defineProperties(this, {
15 | $http: {
16 | get() {
17 | return $http
18 | }
19 | },
20 |
21 | options: {
22 | get() {
23 | return options
24 | }
25 | },
26 |
27 | storage: {
28 | get() {
29 | return storage
30 | }
31 | },
32 |
33 | tokenName: {
34 | get() {
35 | if (this.options.tokenPrefix) {
36 | return [this.options.tokenPrefix, this.options.tokenName].join('_')
37 | } else {
38 | return this.options.tokenName
39 | }
40 | }
41 | }
42 | })
43 |
44 | // Setup request interceptors
45 | if (this.options.bindRequestInterceptor && isFunction(this.options.bindRequestInterceptor) &&
46 | this.options.bindResponseInterceptor && isFunction(this.options.bindResponseInterceptor)) {
47 |
48 | this.options.bindRequestInterceptor.call(this, this)
49 | this.options.bindResponseInterceptor.call(this, this)
50 | } else {
51 | throw new Error('Both request and response interceptors must be functions')
52 | }
53 | }
54 |
55 | /**
56 | * Check if user is authenticated
57 | * @author Sahat Yalkabov
58 | * @copyright Method taken from https://github.com/sahat/satellizer
59 | * @return {Boolean}
60 | */
61 | // isAuthenticated() {
62 | // let token = this.storage.getItem(this.tokenName)
63 |
64 | // if (token) { // Token is present
65 | // if (token.split('.').length === 3) { // Token with a valid JWT format XXX.YYY.ZZZ
66 | // try { // Could be a valid JWT or an access token with the same format
67 | // const base64Url = token.split('.')[1];
68 | // const base64 = base64Url.replace('-', '+').replace('_', '/');
69 | // const exp = JSON.parse(window.atob(base64)).exp;
70 | // if (typeof exp === 'number') { // JWT with an optonal expiration claims
71 | // return Math.round(new Date().getTime() / 1000) < exp;
72 | // }
73 | // } catch (e) {
74 | // return true; // Pass: Non-JWT token that looks like JWT
75 | // }
76 | // }
77 | // return true; // Pass: All other tokens
78 | // }
79 | // return false
80 | // }
81 |
82 | /**
83 | * Get token if user is authenticated
84 | * @return {String} Authentication token
85 | */
86 | getToken() {
87 | return this.storage.getItem(this.tokenName)
88 | }
89 |
90 | /**
91 | * Set new authentication token
92 | * @param {String|Object} token
93 | */
94 | // setToken(response) {
95 | // if (response[this.options.responseDataKey]) {
96 | // response = response[this.options.responseDataKey];
97 | // }
98 |
99 | // let token;
100 | // if (response.access_token) {
101 | // if (isObject(response.access_token) && isObject(response.access_token[this.options.responseDataKey])) {
102 | // response = response.access_token
103 | // } else if (isString(response.access_token)) {
104 | // token = response.access_token
105 | // }
106 | // }
107 |
108 | // if (!token && response) {
109 | // token = response[this.options.tokenName]
110 | // }
111 |
112 | // if (token) {
113 | // this.storage.setItem(this.tokenName, token)
114 | // }
115 | // }
116 |
117 | // getPayload() {
118 | // const token = this.storage.getItem(this.tokenName);
119 |
120 | // if (token && token.split('.').length === 3) {
121 | // try {
122 | // const base64Url = token.split('.')[1];
123 | // const base64 = base64Url.replace('-', '+').replace('_', '/');
124 | // return JSON.parse(decodeBase64(base64));
125 | // } catch (e) {}
126 | // }
127 | // }
128 |
129 | /**
130 | * Login user using email and password
131 | * @param {Object} user User data
132 | * @param {Object} requestOptions Request options
133 | * @return {Promise} Request promise
134 | */
135 | // login(user, requestOptions) {
136 | // requestOptions = requestOptions || {}
137 | // requestOptions.url = requestOptions.url ? requestOptions.url : joinUrl(this.options.baseUrl, this.options.loginUrl)
138 | // requestOptions[this.options.requestDataKey] = user || requestOptions[this.options.requestDataKey]
139 | // requestOptions.method = requestOptions.method || 'POST'
140 | // requestOptions.withCredentials = requestOptions.withCredentials || this.options.withCredentials
141 |
142 | // return this.$http(requestOptions).then((response) => {
143 | // this.setToken(response)
144 | // return response
145 | // })
146 | // }
147 |
148 | /**
149 | * Register new user
150 | * @param {Object} user User data
151 | * @param {Object} requestOptions Request options
152 | * @return {Promise} Request promise
153 | */
154 | // register(user, requestOptions) {
155 | // requestOptions = requestOptions || {}
156 | // requestOptions.url = requestOptions.url ? requestOptions.url : joinUrl(this.options.baseUrl, this.options.registerUrl)
157 | // requestOptions[this.options.requestDataKey] = user || requestOptions[this.options.requestDataKey]
158 | // requestOptions.method = requestOptions.method || 'POST'
159 | // requestOptions.withCredentials = requestOptions.withCredentials || this.options.withCredentials
160 |
161 | // return this.$http(requestOptions).then((response) => {
162 | // this.setToken(response)
163 | // return response
164 | // })
165 | // }
166 |
167 | /**
168 | * Logout current user
169 | * @param {Object} requestOptions Logout request options object
170 | * @return {Promise} Request promise
171 | */
172 | // logout(requestOptions) {
173 | // if (!this.isAuthenticated()) {
174 | // return Promise.reject(new Error('There is no currently authenticated user'))
175 | // }
176 |
177 | // requestOptions = requestOptions || {}
178 | // requestOptions.url = requestOptions.logoutUrl || this.options.logoutUrl
179 |
180 | // if (requestOptions.url) {
181 | // requestOptions.method = requestOptions.method || 'POST'
182 | // requestOptions.withCredentials = requestOptions.withCredentials || this.options.withCredentials
183 |
184 | // return this.$http(requestOptions).then((response) => {
185 | // this.storage.removeItem(this.tokenName)
186 | // })
187 | // } else {
188 | // this.storage.removeItem(this.tokenName)
189 | // return Promise.resolve();
190 | // }
191 | // }
192 |
193 | /**
194 | * Authenticate user using authentication provider
195 | *
196 | * @param {String} provider Provider name
197 | * @param {Object} userData User data
198 | * @param {Object} requestOptions Request options
199 | * @return {Promise} Request promise
200 | */
201 | authenticate(provider, userData, requestOptions) {
202 | return new Promise((resolve, reject) => {
203 | var providerConfig = this.options.providers[provider]
204 | if (!providerConfig) {
205 | return reject(new Error('Unknown provider'))
206 | }
207 |
208 | let providerInstance;
209 | switch (providerConfig.oauthType) {
210 | case '1.0':
211 | providerInstance = new OAuth1(this.$http, this.storage, providerConfig, this.options)
212 | break
213 | case '2.0':
214 | providerInstance = new OAuth2(this.$http, this.storage, providerConfig, this.options)
215 | break
216 | default:
217 | return reject(new Error('Invalid OAuth type'))
218 | break
219 | }
220 |
221 | return providerInstance.init(userData).then((response) => {
222 | return resolve(response)
223 |
224 | }).catch(err => reject(err))
225 | })
226 | }
227 |
228 | }
229 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import './utils.js'
2 | import Promise from './promise.js'
3 | import VueSocialauth from './authenticate.js'
4 |
5 | /**
6 | * VueSocialauth plugin
7 | * @param {Object} Vue
8 | * @param {Object} options
9 | */
10 | function plugin(Vue, options) {
11 | if (plugin.installed) {
12 | return
13 | }
14 | plugin.installed = true
15 |
16 | const property = options.property || '$auth'
17 |
18 | let vueAuthInstance = null;
19 | Object.defineProperties(Vue.prototype, {
20 | [property]: {
21 | get() {
22 | if (!vueAuthInstance) {
23 | // Request handler library not found, throw error
24 | // verified vue or nuxt instance
25 | if (this.$axios) {
26 | vueAuthInstance = new VueSocialauth(this.$axios, options)
27 | } else if (this.$http) {
28 | vueAuthInstance = new VueSocialauth(this.$http, options)
29 | } else {
30 | throw new Error('Request handler instance not found')
31 | }
32 | }
33 | return vueAuthInstance
34 | }
35 | }
36 | })
37 | }
38 |
39 | /**
40 | * External factory helper for ES5 and CommonJS
41 | * @param {Object} $http Instance of request handling library
42 | * @param {Object} options Configuration object
43 | * @return {VueSocialauth} VueSocialauth instance
44 | */
45 | plugin.factory = function ($http, options) {
46 | return new VueSocialauth($http, options)
47 | }
48 |
49 | export default plugin
50 |
--------------------------------------------------------------------------------
/src/oauth/oauth1.js:
--------------------------------------------------------------------------------
1 | import OAuthPopup from './popup.js'
2 | import { objectExtend, isString, isObject, isFunction, joinUrl } from '../utils.js'
3 |
4 | const defaultProviderConfig = {
5 | name: null,
6 | url: null,
7 | authorizationEndpoint: null,
8 | scope: null,
9 | scopePrefix: null,
10 | scopeDelimiter: null,
11 | redirectUri: null,
12 | requiredUrlParams: null,
13 | defaultUrlParams: null,
14 | oauthType: '1.0',
15 | popupOptions: {}
16 | }
17 |
18 | export default class OAuth {
19 | constructor($http, storage, providerConfig, options) {
20 | this.$http = $http
21 | this.storage = storage
22 | this.providerConfig = objectExtend({}, defaultProviderConfig)
23 | this.providerConfig = objectExtend(this.providerConfig, providerConfig)
24 | this.options = options
25 | }
26 |
27 | /**
28 | * Initialize OAuth1 process
29 | * @param {Object} userData User data
30 | * @return {Promise}
31 | */
32 | init(userData) {
33 | this.oauthPopup = new OAuthPopup('about:blank', this.providerConfig.name, this.providerConfig.popupOptions)
34 |
35 | if (window && !window['cordova']) {
36 | this.oauthPopup.open(this.providerConfig.redirectUri, true)
37 | }
38 |
39 | return this.getRequestToken().then((response) => {
40 | return this.openPopup(response).then((popupResponse) => {
41 | return this.exchangeForToken(popupResponse, userData)
42 | })
43 | })
44 | }
45 |
46 | /**
47 | * Get OAuth1 request token
48 | * @return {Promise}
49 | */
50 | getRequestToken() {
51 | let requestOptions = {}
52 | requestOptions.method = 'POST'
53 | requestOptions[this.options.requestDataKey] = objectExtend({}, this.providerConfig)
54 | requestOptions.withCredentials = this.options.withCredentials
55 | if (this.options.baseUrl) {
56 | requestOptions.url = joinUrl(this.options.baseUrl, this.providerConfig.url)
57 | } else {
58 | requestOptions.url = this.providerConfig.url
59 | }
60 |
61 | return this.$http(requestOptions)
62 | }
63 |
64 | /**
65 | * Open OAuth1 popup
66 | * @param {Object} response Response object containing request token
67 | * @return {Promise}
68 | */
69 | openPopup(response) {
70 | const url = [this.providerConfig.authorizationEndpoint, this.buildQueryString(response[this.options.responseDataKey])].join('?');
71 |
72 | this.oauthPopup.popup.location = url
73 | if (window && window['cordova']) {
74 | return this.oauthPopup.open(this.providerConfig.redirectUri)
75 | } else {
76 | return this.oauthPopup.pooling(this.providerConfig.redirectUri)
77 | }
78 | }
79 |
80 | /**
81 | * Exchange token and token verifier for access token
82 | * @param {Object} oauth OAuth data containing token and token verifier
83 | * @param {Object} userData User data
84 | * @return {Promise}
85 | */
86 | exchangeForToken(oauth, userData) {
87 | let payload = objectExtend({}, userData)
88 | payload = objectExtend(payload, oauth)
89 | let requestOptions = {}
90 | requestOptions.method = 'POST'
91 | requestOptions[this.options.requestDataKey] = payload
92 | requestOptions.withCredentials = this.options.withCredentials
93 | if (this.options.baseUrl) {
94 | requestOptions.url = joinUrl(this.options.baseUrl, this.providerConfig.url)
95 | } else {
96 | requestOptions.url = this.providerConfig.url
97 | }
98 | return this.$http(requestOptions)
99 | }
100 |
101 | buildQueryString(params) {
102 | const parsedParams = [];
103 | for (var key in params) {
104 | let value = params[key]
105 | parsedParams.push(encodeURIComponent(key) + '=' + encodeURIComponent(value));
106 | }
107 | return parsedParams.join('&');
108 | }
109 | }
--------------------------------------------------------------------------------
/src/oauth/oauth2.js:
--------------------------------------------------------------------------------
1 | import OAuthPopup from './popup.js'
2 | import { camelCase, isFunction, isString, objectExtend, joinUrl } from '../utils.js'
3 |
4 | /**
5 | * Default provider configuration
6 | * @type {Object}
7 | */
8 | const defaultProviderConfig = {
9 | name: null,
10 | url: null,
11 | clientId: null,
12 | authorizationEndpoint: null,
13 | redirectUri: null,
14 | scope: null,
15 | scopePrefix: null,
16 | scopeDelimiter: null,
17 | state: null,
18 | requiredUrlParams: null,
19 | defaultUrlParams: ['response_type', 'client_id', 'redirect_uri'],
20 | responseType: 'code',
21 | responseParams: {
22 | code: 'code',
23 | clientId: 'clientId',
24 | redirectUri: 'redirectUri'
25 | },
26 | oauthType: '2.0',
27 | popupOptions: {}
28 | }
29 |
30 | export default class OAuth2 {
31 | constructor($http, storage, providerConfig, options) {
32 | this.$http = $http
33 | this.storage = storage
34 | this.providerConfig = objectExtend({}, defaultProviderConfig)
35 | this.providerConfig = objectExtend(this.providerConfig, providerConfig)
36 | this.options = options
37 | }
38 |
39 | init(userData) {
40 | let stateName = this.providerConfig.name + '_state';
41 | if (isFunction(this.providerConfig.state)) {
42 | this.storage.setItem(stateName, this.providerConfig.state())
43 | } else if (isString(this.providerConfig.state)) {
44 | this.storage.setItem(stateName, this.providerConfig.state)
45 | }
46 |
47 | let url = [this.providerConfig.authorizationEndpoint, this._stringifyRequestParams()].join('?')
48 |
49 | this.oauthPopup = new OAuthPopup(url, this.providerConfig.name, this.providerConfig.popupOptions)
50 |
51 | return new Promise((resolve, reject) => {
52 | this.oauthPopup.open(this.providerConfig.redirectUri).then((response) => {
53 | if (this.providerConfig.responseType === 'code' || !this.providerConfig.url) {
54 | return resolve(response)
55 | }
56 |
57 | if (response.state && response.state !== this.storage.getItem(stateName)) {
58 | return reject(new Error('State parameter value does not match original OAuth request state value'))
59 | }
60 |
61 | resolve(this.exchangeForToken(response, userData))
62 | }).catch((err) => {
63 | reject(err)
64 | })
65 | })
66 | }
67 |
68 | /**
69 | * Exchange temporary oauth data for access token
70 | * @author Sahat Yalkabov
71 | * @copyright Method taken from https://github.com/sahat/satellizer
72 | *
73 | * @param {[type]} oauth [description]
74 | * @param {[type]} userData [description]
75 | * @return {[type]} [description]
76 | */
77 | exchangeForToken(oauth, userData) {
78 | let payload = objectExtend({}, userData)
79 |
80 | for (let key in defaultProviderConfig.responseParams) {
81 | let value = defaultProviderConfig[key]
82 |
83 | switch(key) {
84 | case 'code':
85 | payload[key] = oauth.code
86 | break
87 | case 'clientId':
88 | payload[key] = this.providerConfig.clientId
89 | break
90 | case 'redirectUri':
91 | payload[key] = this.providerConfig.redirectUri
92 | break
93 | default:
94 | payload[key] = oauth[key]
95 | }
96 | }
97 |
98 | if (oauth.state) {
99 | payload.state = oauth.state
100 | }
101 |
102 | let exchangeTokenUrl
103 | if (this.options.baseUrl) {
104 | exchangeTokenUrl = joinUrl(this.options.baseUrl, this.providerConfig.url)
105 | } else {
106 | exchangeTokenUrl = this.providerConfig.url
107 | }
108 |
109 | return this.$http.post(exchangeTokenUrl, payload, {
110 | withCredentials: this.options.withCredentials
111 | })
112 | }
113 |
114 | /**
115 | * Stringify oauth params
116 | * @author Sahat Yalkabov
117 | * @copyright Method taken from https://github.com/sahat/satellizer
118 | *
119 | * @return {String}
120 | */
121 | _stringifyRequestParams() {
122 | let keyValuePairs = []
123 | let paramCategories = ['defaultUrlParams', 'requiredUrlParams', 'optionalUrlParams']
124 |
125 | paramCategories.forEach((categoryName) => {
126 | if (!this.providerConfig[categoryName]) return
127 | if (!Array.isArray(this.providerConfig[categoryName])) return
128 |
129 | this.providerConfig[categoryName].forEach((paramName) => {
130 | let camelCaseParamName = camelCase(paramName)
131 | let paramValue = isFunction(this.providerConfig[paramName]) ? this.providerConfig[paramName]() : this.providerConfig[camelCaseParamName]
132 |
133 | if (paramName === 'redirect_uri' && !paramValue) return
134 |
135 | if (paramName === 'state') {
136 | let stateName = this.providerConfig.name + '_state';
137 | paramValue = encodeURIComponent(this.storage.getItem(stateName));
138 | }
139 | if (paramName === 'scope' && Array.isArray(paramValue)) {
140 | paramValue = paramValue.join(this.providerConfig.scopeDelimiter);
141 | if (this.providerConfig.scopePrefix) {
142 | paramValue = [this.providerConfig.scopePrefix, paramValue].join(this.providerConfig.scopeDelimiter);
143 | }
144 | }
145 |
146 | keyValuePairs.push([paramName, paramValue])
147 | })
148 | })
149 |
150 | return keyValuePairs.map((param) => {
151 | return param.join('=')
152 | }).join('&')
153 | }
154 | }
--------------------------------------------------------------------------------
/src/oauth/popup.js:
--------------------------------------------------------------------------------
1 | import Promise from '../promise.js'
2 | import { objectExtend, parseQueryString, getFullUrlPath, isUndefined } from '../utils.js'
3 |
4 | /**
5 | * OAuth2 popup management class
6 | *
7 | * @author Sahat Yalkabov
8 | * @copyright Class mostly taken from https://github.com/sahat/satellizer
9 | * and adjusted to fit vue-social-auth library
10 | */
11 | export default class OAuthPopup {
12 | constructor(url, name, popupOptions) {
13 | this.popup = null
14 | this.url = url
15 | this.name = name
16 | this.popupOptions = popupOptions
17 | }
18 |
19 | open(redirectUri, skipPooling) {
20 | try {
21 | this.popup = window.open(this.url, this.name, this._stringifyOptions())
22 | if (this.popup && this.popup.focus) {
23 | this.popup.focus()
24 | }
25 |
26 | if (skipPooling) {
27 | return Promise.resolve()
28 | } else {
29 | return this.pooling(redirectUri)
30 | }
31 | } catch(e) {
32 | return Promise.reject(new Error('OAuth popup error occurred'))
33 | }
34 | }
35 |
36 | pooling(redirectUri) {
37 | return new Promise((resolve, reject) => {
38 | const redirectUriParser = document.createElement('a')
39 | redirectUriParser.href = redirectUri
40 | const redirectUriPath = getFullUrlPath(redirectUriParser)
41 |
42 | let poolingInterval = setInterval(() => {
43 | if (!this.popup || this.popup.closed || this.popup.closed === undefined) {
44 | clearInterval(poolingInterval)
45 | poolingInterval = null
46 | reject(new Error('Auth popup window closed'))
47 | }
48 |
49 | try {
50 | const popupWindowPath = getFullUrlPath(this.popup.location)
51 |
52 | if (popupWindowPath === redirectUriPath) {
53 | if (this.popup.location.search || this.popup.location.hash) {
54 | const query = parseQueryString(this.popup.location.search.substring(1).replace(/\/$/, ''));
55 | const hash = parseQueryString(this.popup.location.hash.substring(1).replace(/[\/$]/, ''));
56 | let params = objectExtend({}, query);
57 | params = objectExtend(params, hash)
58 |
59 | if (params.error) {
60 | reject(new Error(params.error));
61 | } else {
62 | resolve(params);
63 | }
64 | } else {
65 | reject(new Error('OAuth redirect has occurred but no query or hash parameters were found.'))
66 | }
67 |
68 | clearInterval(poolingInterval)
69 | poolingInterval = null
70 | this.popup.close()
71 | }
72 | } catch(e) {
73 | // Ignore DOMException: Blocked a frame with origin from accessing a cross-origin frame.
74 | }
75 | }, 250)
76 | })
77 | }
78 |
79 | _stringifyOptions() {
80 | let options = []
81 | for (var optionKey in this.popupOptions) {
82 | if (!isUndefined(this.popupOptions[optionKey])) {
83 | options.push(`${optionKey}=${this.popupOptions[optionKey]}`)
84 | }
85 | }
86 | return options.join(',')
87 | }
88 | }
--------------------------------------------------------------------------------
/src/options.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Default configuration
3 | */
4 | export default {
5 | baseUrl: null,
6 | tokenName: 'token',
7 | tokenPrefix: 'vueauth',
8 | tokenHeader: 'Authorization',
9 | tokenType: 'Bearer',
10 | loginUrl: '/auth/login',
11 | registerUrl: '/auth/register',
12 | logoutUrl: null,
13 | storageType: 'localStorage',
14 | storageNamespace: 'vue-social-auth',
15 | cookieStorage: {
16 | domain: window.location.hostname,
17 | path: '/',
18 | secure: false
19 | },
20 | requestDataKey: 'data',
21 | responseDataKey: 'data',
22 |
23 | /**
24 | * Default request interceptor for Axios library
25 | * @context {VueSocialauth}
26 | */
27 | bindRequestInterceptor: function ($auth) {
28 |
29 | const tokenHeader = $auth.options.tokenHeader;
30 |
31 | $auth.$http.interceptors.request.use((config) => {
32 | delete config.headers[tokenHeader]
33 | return config
34 | })
35 |
36 |
37 | },
38 |
39 | /**
40 | * Default response interceptor for Axios library
41 | * @contect {VueSocialauth}
42 | */
43 | bindResponseInterceptor: function ($auth) {
44 | $auth.$http.interceptors.response.use((response) => {
45 | return response
46 | })
47 | },
48 |
49 | providers: {
50 | facebook: {
51 | name: 'facebook',
52 | url: '/auth/facebook',
53 | authorizationEndpoint: 'https://www.facebook.com/v2.5/dialog/oauth',
54 | redirectUri: window.location.origin + '/',
55 | requiredUrlParams: ['display', 'scope'],
56 | scope: ['email'],
57 | scopeDelimiter: ',',
58 | display: 'popup',
59 | oauthType: '2.0',
60 | popupOptions: { width: 580, height: 400 }
61 | },
62 |
63 | google: {
64 | name: 'google',
65 | url: '/auth/google',
66 | authorizationEndpoint: 'https://accounts.google.com/o/oauth2/auth',
67 | redirectUri: window.location.origin,
68 | requiredUrlParams: ['scope'],
69 | optionalUrlParams: ['display'],
70 | scope: ['profile', 'email'],
71 | scopePrefix: 'openid',
72 | scopeDelimiter: ' ',
73 | display: 'popup',
74 | oauthType: '2.0',
75 | popupOptions: { width: 452, height: 633 }
76 | },
77 |
78 | github: {
79 | name: 'github',
80 | url: '/auth/github',
81 | authorizationEndpoint: 'https://github.com/login/oauth/authorize',
82 | redirectUri: window.location.origin,
83 | optionalUrlParams: ['scope'],
84 | scope: ['user:email'],
85 | scopeDelimiter: ' ',
86 | oauthType: '2.0',
87 | popupOptions: { width: 1020, height: 618 }
88 | },
89 |
90 | instagram: {
91 | name: 'instagram',
92 | url: '/auth/instagram',
93 | authorizationEndpoint: 'https://api.instagram.com/oauth/authorize',
94 | redirectUri: window.location.origin,
95 | requiredUrlParams: ['scope'],
96 | scope: ['basic'],
97 | scopeDelimiter: '+',
98 | oauthType: '2.0',
99 | popupOptions: { width: null, height: null }
100 | },
101 |
102 | twitter: {
103 | name: 'twitter',
104 | url: '/auth/twitter',
105 | authorizationEndpoint: 'https://api.twitter.com/oauth/authenticate',
106 | redirectUri: window.location.origin,
107 | oauthType: '1.0',
108 | popupOptions: { width: 495, height: 645 }
109 | },
110 |
111 | bitbucket: {
112 | name: 'bitbucket',
113 | url: '/auth/bitbucket',
114 | authorizationEndpoint: 'https://bitbucket.org/site/oauth2/authorize',
115 | redirectUri: window.location.origin + '/',
116 | optionalUrlParams: ['scope'],
117 | scope: ['email'],
118 | scopeDelimiter: ' ',
119 | oauthType: '2.0',
120 | popupOptions: { width: 1020, height: 618 }
121 | },
122 |
123 | linkedin: {
124 | name: 'linkedin',
125 | url: '/auth/linkedin',
126 | authorizationEndpoint: 'https://www.linkedin.com/oauth/v2/authorization',
127 | redirectUri: window.location.origin,
128 | requiredUrlParams: ['state','scope'],
129 | scope: ['r_liteprofile','r_emailaddress'],
130 | scopeDelimiter: ' ',
131 | state: 'STATE',
132 | oauthType: '2.0',
133 | popupOptions: { width: 527, height: 582 }
134 | },
135 |
136 | vkontakte: {
137 | name: 'vkontakte',
138 | url: '/auth/vkontakte',
139 | authorizationEndpoint: 'https://oauth.vk.com/authorize',
140 | redirectUri: window.location.origin + '/',
141 | requiredUrlParams: ['scope'],
142 | scope: ['email'],
143 | scopeDelimiter: ',',
144 | display: 'popup',
145 | oauthType: '2.0',
146 | popupOptions: { width: 580, height: 400 }
147 | },
148 |
149 | live: {
150 | name: 'live',
151 | url: '/auth/live',
152 | authorizationEndpoint: 'https://login.live.com/oauth20_authorize.srf',
153 | redirectUri: window.location.origin,
154 | requiredUrlParams: ['display', 'scope'],
155 | scope: ['wl.emails'],
156 | scopeDelimiter: ' ',
157 | display: 'popup',
158 | oauthType: '2.0',
159 | popupOptions: { width: 500, height: 560 }
160 | },
161 |
162 | oauth1: {
163 | name: null,
164 | url: '/auth/oauth1',
165 | authorizationEndpoint: null,
166 | redirectUri: window.location.origin,
167 | oauthType: '1.0',
168 | popupOptions: null
169 | },
170 |
171 | oauth2: {
172 | name: null,
173 | url: '/auth/oauth2',
174 | clientId: null,
175 | redirectUri: window.location.origin,
176 | authorizationEndpoint: null,
177 | defaultUrlParams: ['response_type', 'client_id', 'redirect_uri'],
178 | requiredUrlParams: null,
179 | optionalUrlParams: null,
180 | scope: null,
181 | scopePrefix: null,
182 | scopeDelimiter: null,
183 | state: null,
184 | oauthType: '2.0',
185 | popupOptions: null,
186 | responseType: 'code',
187 | responseParams: {
188 | code: 'code',
189 | clientId: 'clientId',
190 | redirectUri: 'redirectUri'
191 | }
192 | }
193 | }
194 | }
195 |
--------------------------------------------------------------------------------
/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') throw new TypeError('Promises must be constructed via new');
16 | if (typeof fn !== 'function') throw new TypeError('not a function');
17 | this._state = 0;
18 | this._handled = false;
19 | this._value = undefined;
20 | this._deferreds = [];
21 |
22 | doResolve(fn, this);
23 | }
24 |
25 | function handle(self, deferred) {
26 | while (self._state === 3) {
27 | self = self._value;
28 | }
29 | if (self._state === 0) {
30 | self._deferreds.push(deferred);
31 | return;
32 | }
33 | self._handled = true;
34 | Promise._immediateFn(function () {
35 | var cb = self._state === 1 ? deferred.onFulfilled : deferred.onRejected;
36 | if (cb === null) {
37 | (self._state === 1 ? resolve : reject)(deferred.promise, self._value);
38 | return;
39 | }
40 | var ret;
41 | try {
42 | ret = cb(self._value);
43 | } catch (e) {
44 | reject(deferred.promise, e);
45 | return;
46 | }
47 | resolve(deferred.promise, ret);
48 | });
49 | }
50 |
51 | function resolve(self, newValue) {
52 | try {
53 | // Promise Resolution Procedure: https://github.com/promises-aplus/promises-spec#the-promise-resolution-procedure
54 | if (newValue === self) throw new TypeError('A promise cannot be resolved with itself.');
55 | if (newValue && (typeof newValue === 'object' || typeof newValue === 'function')) {
56 | var then = newValue.then;
57 | if (newValue instanceof Promise) {
58 | self._state = 3;
59 | self._value = newValue;
60 | finale(self);
61 | return;
62 | } else if (typeof then === 'function') {
63 | doResolve(bind(then, newValue), self);
64 | return;
65 | }
66 | }
67 | self._state = 1;
68 | self._value = newValue;
69 | finale(self);
70 | } catch (e) {
71 | reject(self, e);
72 | }
73 | }
74 |
75 | function reject(self, newValue) {
76 | self._state = 2;
77 | self._value = newValue;
78 | finale(self);
79 | }
80 |
81 | function finale(self) {
82 | if (self._state === 2 && self._deferreds.length === 0) {
83 | Promise._immediateFn(function() {
84 | if (!self._handled) {
85 | Promise._unhandledRejectionFn(self._value);
86 | }
87 | });
88 | }
89 |
90 | for (var i = 0, len = self._deferreds.length; i < len; i++) {
91 | handle(self, self._deferreds[i]);
92 | }
93 | self._deferreds = null;
94 | }
95 |
96 | function Handler(onFulfilled, onRejected, promise) {
97 | this.onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : null;
98 | this.onRejected = typeof onRejected === 'function' ? onRejected : null;
99 | this.promise = promise;
100 | }
101 |
102 | /**
103 | * Take a potentially misbehaving resolver function and make sure
104 | * onFulfilled and onRejected are only called once.
105 | *
106 | * Makes no guarantees about asynchrony.
107 | */
108 | function doResolve(fn, self) {
109 | var done = false;
110 | try {
111 | fn(function (value) {
112 | if (done) return;
113 | done = true;
114 | resolve(self, value);
115 | }, function (reason) {
116 | if (done) return;
117 | done = true;
118 | reject(self, reason);
119 | });
120 | } catch (ex) {
121 | if (done) return;
122 | done = true;
123 | reject(self, ex);
124 | }
125 | }
126 |
127 | Promise.prototype['catch'] = function (onRejected) {
128 | return this.then(null, onRejected);
129 | };
130 |
131 | Promise.prototype.then = function (onFulfilled, onRejected) {
132 | var prom = new (this.constructor)(noop);
133 |
134 | handle(this, new Handler(onFulfilled, onRejected, prom));
135 | return prom;
136 | };
137 |
138 | Promise.all = function (arr) {
139 | var args = Array.prototype.slice.call(arr);
140 |
141 | return new Promise(function (resolve, reject) {
142 | if (args.length === 0) return resolve([]);
143 | var remaining = args.length;
144 |
145 | function res(i, val) {
146 | try {
147 | if (val && (typeof val === 'object' || typeof val === 'function')) {
148 | var then = val.then;
149 | if (typeof then === 'function') {
150 | then.call(val, function (val) {
151 | res(i, val);
152 | }, reject);
153 | return;
154 | }
155 | }
156 | args[i] = val;
157 | if (--remaining === 0) {
158 | resolve(args);
159 | }
160 | } catch (ex) {
161 | reject(ex);
162 | }
163 | }
164 |
165 | for (var i = 0; i < args.length; i++) {
166 | res(i, args[i]);
167 | }
168 | });
169 | };
170 |
171 | Promise.resolve = function (value) {
172 | if (value && typeof value === 'object' && value.constructor === Promise) {
173 | return value;
174 | }
175 |
176 | return new Promise(function (resolve) {
177 | resolve(value);
178 | });
179 | };
180 |
181 | Promise.reject = function (value) {
182 | return new Promise(function (resolve, reject) {
183 | reject(value);
184 | });
185 | };
186 |
187 | Promise.race = function (values) {
188 | return new Promise(function (resolve, reject) {
189 | for (var i = 0, len = values.length; i < len; i++) {
190 | values[i].then(resolve, reject);
191 | }
192 | });
193 | };
194 |
195 | // Use polyfill for setImmediate for performance gains
196 | Promise._immediateFn = (typeof setImmediate === 'function' && function (fn) { setImmediate(fn); }) ||
197 | function (fn) {
198 | setTimeoutFunc(fn, 0);
199 | };
200 |
201 | Promise._unhandledRejectionFn = function _unhandledRejectionFn(err) {
202 | if (typeof console !== 'undefined' && console) {
203 | console.warn('Possible Unhandled Promise Rejection:', err); // eslint-disable-line no-console
204 | }
205 | };
206 |
207 | /**
208 | * Set the immediate function to execute callbacks
209 | * @param fn {function} Function to execute
210 | * @deprecated
211 | */
212 | Promise._setImmediateFn = function _setImmediateFn(fn) {
213 | Promise._immediateFn = fn;
214 | };
215 |
216 | /**
217 | * Change the function to execute on unhandled rejection
218 | * @param {function} fn Function to execute on unhandled rejection
219 | * @deprecated
220 | */
221 | Promise._setUnhandledRejectionFn = function _setUnhandledRejectionFn(fn) {
222 | Promise._unhandledRejectionFn = fn;
223 | };
224 |
225 | export default Promise;
--------------------------------------------------------------------------------
/src/storage.js:
--------------------------------------------------------------------------------
1 | import CookieStorage from './storage/cookie-storage.js';
2 | import LocalStorage from './storage/local-storage.js'
3 | import MemoryStorage from './storage/memory-storage.js'
4 | import SessionStorage from './storage/session-storage.js'
5 |
6 | export default function StorageFactory(options) {
7 | switch (options.storageType) {
8 | case 'localStorage':
9 | try {
10 | window.localStorage.setItem('testKey', 'test')
11 | window.localStorage.removeItem('testKey')
12 | return new LocalStorage(options.storageNamespace)
13 | } catch(e) {}
14 |
15 | case 'sessionStorage':
16 | try {
17 | window.sessionStorage.setItem('testKey', 'test')
18 | window.sessionStorage.removeItem('testKey')
19 | return new SessionStorage(options.storageNamespace)
20 | } catch (e) {}
21 |
22 | case 'cookieStorage':
23 | return new CookieStorage(options.cookieStorage);
24 |
25 | case 'memoryStorage':
26 | default:
27 | return new MemoryStorage(options.storageNamespace)
28 | break;
29 | }
30 | }
--------------------------------------------------------------------------------
/src/storage/cookie-storage.js:
--------------------------------------------------------------------------------
1 | import {
2 | objectExtend,
3 | formatCookie,
4 | parseCookies
5 | } from '../utils.js';
6 |
7 | class CookieStorage {
8 | constructor(defaultOptions) {
9 | this._defaultOptions = objectExtend({
10 | domain: window.location.hostname,
11 | expires: null,
12 | path: '/',
13 | secure: false
14 | }, defaultOptions);
15 | }
16 |
17 | setItem(key, value) {
18 | const options = objectExtend({}, this._defaultOptions);
19 | const cookie = formatCookie(key, value, options);
20 | this._setCookie(cookie);
21 | }
22 |
23 | getItem(key) {
24 | const cookies = parseCookies(this._getCookie());
25 | return cookies.hasOwnProperty(key) ? cookies[key] : null;
26 | }
27 |
28 | removeItem(key) {
29 | const value = '';
30 | const defaultOptions = objectExtend({}, this._defaultOptions);
31 | const options = objectExtend(defaultOptions, {
32 | expires: new Date(0)
33 | });
34 | const cookie = formatCookie(key, value, options);
35 | this._setCookie(cookie);
36 | }
37 |
38 | _getCookie() {
39 | return typeof document === 'undefined'
40 | ? '' : typeof document.cookie === 'undefined'
41 | ? '' : document.cookie;
42 | }
43 |
44 | _setCookie(cookie) {
45 | document.cookie = cookie;
46 | }
47 | }
48 |
49 | export default CookieStorage
--------------------------------------------------------------------------------
/src/storage/local-storage.js:
--------------------------------------------------------------------------------
1 | class LocalStorage {
2 | constructor(namespace) {
3 | this.namespace = namespace || null
4 | }
5 |
6 | setItem(key, value) {
7 | window.localStorage.setItem(this._getStorageKey(key), value)
8 | }
9 |
10 | getItem(key) {
11 | return window.localStorage.getItem(this._getStorageKey(key))
12 | }
13 |
14 | removeItem(key) {
15 | window.localStorage.removeItem(this._getStorageKey(key))
16 | }
17 |
18 | _getStorageKey(key) {
19 | if (this.namespace) {
20 | return [this.namespace, key].join('.')
21 | }
22 | return key;
23 | }
24 | }
25 |
26 | export default LocalStorage
--------------------------------------------------------------------------------
/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
--------------------------------------------------------------------------------
/src/storage/session-storage.js:
--------------------------------------------------------------------------------
1 | class LocalStorage {
2 | constructor(namespace) {
3 | this.namespace = namespace || null
4 | }
5 |
6 | setItem(key, value) {
7 | window.sessionStorage.setItem(this._getStorageKey(key), value)
8 | }
9 |
10 | getItem(key) {
11 | return window.sessionStorage.getItem(this._getStorageKey(key))
12 | }
13 |
14 | removeItem(key) {
15 | window.sessionStorage.removeItem(this._getStorageKey(key))
16 | }
17 |
18 | _getStorageKey(key) {
19 | if (this.namespace) {
20 | return [this.namespace, key].join('.')
21 | }
22 | return key;
23 | }
24 | }
25 |
26 | export default LocalStorage
--------------------------------------------------------------------------------
/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) { // Skip over if undefined or null
14 | for (var nextKey in nextSource) {
15 | // Avoid bugs when hasOwnProperty is shadowed
16 | if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) {
17 | to[nextKey] = nextSource[nextKey];
18 | }
19 | }
20 | }
21 | }
22 | return to;
23 | };
24 | }
25 |
26 | export function camelCase(name) {
27 | return name.replace(/([\:\-\_]+(.))/g, function (_, separator, letter, offset) {
28 | return offset ? letter.toUpperCase() : letter;
29 | });
30 | }
31 |
32 | export function isUndefined(value) {
33 | return typeof value === 'undefined'
34 | }
35 |
36 | export function isDefined(value) {
37 | return typeof value !== 'undefined'
38 | }
39 |
40 | export function isObject(value) {
41 | return value !== null && typeof value === 'object'
42 | }
43 |
44 | export function isString(value) {
45 | return typeof value === 'string'
46 | }
47 |
48 | export function isNumber(value) {
49 | return typeof value === 'number'
50 | }
51 |
52 | export function isFunction(value) {
53 | return typeof value === 'function'
54 | }
55 |
56 | export function objectExtend(a, b) {
57 |
58 | // Don't touch 'null' or 'undefined' objects.
59 | if (a == null || b == null) {
60 | return a;
61 | }
62 |
63 | Object.keys(b).forEach(function (key) {
64 | if (Object.prototype.toString.call(b[key]) == '[object Object]') {
65 | if (Object.prototype.toString.call(a[key]) != '[object Object]') {
66 | a[key] = b[key];
67 | } else {
68 | a[key] = objectExtend(a[key], b[key]);
69 | }
70 | } else {
71 | a[key] = b[key];
72 | }
73 | });
74 |
75 | return a;
76 | };
77 |
78 | /**
79 | * Assemble url from two segments
80 | *
81 | * @author Sahat Yalkabov
82 | * @copyright Method taken from https://github.com/sahat/satellizer
83 | *
84 | * @param {String} baseUrl Base url
85 | * @param {String} url URI
86 | * @return {String}
87 | */
88 | export function joinUrl(baseUrl, url) {
89 | if (/^(?:[a-z]+:)?\/\//i.test(url)) {
90 | return url;
91 | }
92 | let joined = [baseUrl, url].join('/');
93 | let normalize = function (str) {
94 | return str
95 | .replace(/[\/]+/g, '/')
96 | .replace(/\/\?/g, '?')
97 | .replace(/\/\#/g, '#')
98 | .replace(/\:\//g, '://');
99 | };
100 | return normalize(joined);
101 | }
102 |
103 | /**
104 | * Get full path based on current location
105 | *
106 | * @author Sahat Yalkabov
107 | * @copyright Method taken from https://github.com/sahat/satellizer
108 | *
109 | * @param {Location} location
110 | * @return {String}
111 | */
112 | export function getFullUrlPath(location) {
113 | const isHttps = location.protocol === 'https:';
114 | return location.protocol + '//' + location.hostname +
115 | ':' + (location.port || (isHttps ? '443' : '80')) +
116 | (/^\//.test(location.pathname) ? location.pathname : '/' + location.pathname);
117 | }
118 |
119 | /**
120 | * Parse query string variables
121 | *
122 | * @author Sahat Yalkabov
123 | * @copyright Method taken from https://github.com/sahat/satellizer
124 | *
125 | * @param {String} Query string
126 | * @return {String}
127 | */
128 | export function parseQueryString(str) {
129 | let obj = {};
130 | let key;
131 | let value;
132 | (str || '').split('&').forEach((keyValue) => {
133 | if (keyValue) {
134 | value = keyValue.split('=');
135 | key = decodeURIComponent(value[0]);
136 | obj[key] = (!!value[1]) ? decodeURIComponent(value[1]) : true;
137 | }
138 | });
139 | return obj;
140 | }
141 |
142 | /**
143 | * Decode base64 string
144 | * @author Sahat Yalkabov
145 | * @copyright Method taken from https://github.com/sahat/satellizer
146 | *
147 | * @param {String} str base64 encoded string
148 | * @return {Object}
149 | */
150 | export function decodeBase64(str) {
151 | let buffer;
152 | if (typeof module !== 'undefined' && module.exports) {
153 | try {
154 | buffer = require('buffer').Buffer;
155 | } catch (err) {
156 | // noop
157 | }
158 | }
159 |
160 | let fromCharCode = String.fromCharCode;
161 |
162 | let re_btou = new RegExp([
163 | '[\xC0-\xDF][\x80-\xBF]',
164 | '[\xE0-\xEF][\x80-\xBF]{2}',
165 | '[\xF0-\xF7][\x80-\xBF]{3}'
166 | ].join('|'), 'g');
167 |
168 | let cb_btou = function (cccc) {
169 | switch (cccc.length) {
170 | case 4:
171 | let cp = ((0x07 & cccc.charCodeAt(0)) << 18)
172 | | ((0x3f & cccc.charCodeAt(1)) << 12)
173 | | ((0x3f & cccc.charCodeAt(2)) << 6)
174 | | (0x3f & cccc.charCodeAt(3));
175 | let offset = cp - 0x10000;
176 | return (fromCharCode((offset >>> 10) + 0xD800)
177 | + fromCharCode((offset & 0x3FF) + 0xDC00));
178 | case 3:
179 | return fromCharCode(
180 | ((0x0f & cccc.charCodeAt(0)) << 12)
181 | | ((0x3f & cccc.charCodeAt(1)) << 6)
182 | | (0x3f & cccc.charCodeAt(2))
183 | );
184 | default:
185 | return fromCharCode(
186 | ((0x1f & cccc.charCodeAt(0)) << 6)
187 | | (0x3f & cccc.charCodeAt(1))
188 | );
189 | }
190 | };
191 |
192 | let btou = function (b) {
193 | return b.replace(re_btou, cb_btou);
194 | };
195 |
196 | let _decode = buffer ? function (a) {
197 | return (a.constructor === buffer.constructor
198 | ? a : new buffer(a, 'base64')).toString();
199 | }
200 | : function (a) {
201 | return btou(atob(a));
202 | };
203 |
204 | return _decode(
205 | String(str).replace(/[-_]/g, function (m0) {
206 | return m0 === '-' ? '+' : '/';
207 | })
208 | .replace(/[^A-Za-z0-9\+\/]/g, '')
209 | );
210 | }
211 |
212 | export function parseCookies(str) {
213 | if (str.length === 0) return {};
214 | const parsed = {};
215 | const pattern = new RegExp('\\s*;\\s*');
216 | str.split(pattern).forEach((i) => {
217 | const [encodedKey, encodedValue] = i.split('=');
218 | const key = decodeURIComponent(encodedKey);
219 | const value = decodeURIComponent(encodedValue);
220 | parsed[key] = value;
221 | });
222 | return parsed;
223 | };
224 |
225 | export function formatOptions(options) {
226 | const { path, domain, expires, secure } = options;
227 | return [
228 | typeof path === 'undefined' || path === null
229 | ? '' : ';path=' + path,
230 | typeof domain === 'undefined' || domain === null
231 | ? '' : ';domain=' + domain,
232 | typeof expires === 'undefined' || expires === null
233 | ? '' : ';expires=' + expires.toUTCString(),
234 | typeof secure === 'undefined' || secure === null || secure === false
235 | ? '' : ';secure'
236 | ].join('');
237 | };
238 |
239 | export function formatCookie(key, value, options) {
240 | return [
241 | encodeURIComponent(key),
242 | '=',
243 | encodeURIComponent(value),
244 | formatOptions(options)
245 | ].join('');
246 | };
247 |
--------------------------------------------------------------------------------