Advertisement
Guest User

Untitled

a guest
Jan 27th, 2020
128
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. import getProp from 'dotprop'
  2.  
  3. import Storage from './storage'
  4. import { routeOption, isRelativeURL, isSet, isSameURL } from './utilities'
  5.  
  6. export default class Auth {
  7.   constructor (ctx, options) {
  8.     this.ctx = ctx
  9.     this.options = options
  10.  
  11.     // Strategies
  12.     this.strategies = {}
  13.  
  14.     // Error listeners
  15.     this._errorListeners = []
  16.  
  17.     // Redirect listeners
  18.     this._redirectListeners = []
  19.  
  20.     // Storage & State
  21.     options.initialState = { user: null, loggedIn: false }
  22.     const storage = new Storage(ctx, options)
  23.  
  24.     this.$storage = storage
  25.     this.$state = storage.state
  26.   }
  27.  
  28.   async init () {
  29.     // Reset on error
  30.     if (this.options.resetOnError) {
  31.       this.onError((...args) => {
  32.         if (typeof (this.options.resetOnError) !== 'function' || this.options.resetOnError(...args)) {
  33.           this.reset()
  34.         }
  35.       })
  36.     }
  37.  
  38.     // Restore strategy
  39.     this.$storage.syncUniversal('strategy', this.options.defaultStrategy)
  40.  
  41.     // Set default strategy if current one is invalid
  42.     if (!this.strategy) {
  43.       this.$storage.setUniversal('strategy', this.options.defaultStrategy)
  44.  
  45.       // Give up if still invalid
  46.       if (!this.strategy) {
  47.         return Promise.resolve()
  48.       }
  49.     }
  50.  
  51.     try {
  52.       // Call mounted for active strategy on initial load
  53.       await this.mounted()
  54.     } catch (error) {
  55.       this.callOnError(error)
  56.     } finally {
  57.       // Watch for loggedIn changes only in client side
  58.       if (process.client && this.options.watchLoggedIn) {
  59.         this.$storage.watchState('loggedIn', loggedIn => {
  60.           if (!routeOption(this.ctx.route, 'auth', false)) {
  61.             this.redirect(loggedIn ? 'home' : 'logout')
  62.           }
  63.         })
  64.       }
  65.     }
  66.   }
  67.  
  68.   // Backward compatibility
  69.   get state () {
  70.     if (!this._state_warn_shown) {
  71.       this._state_warn_shown = true
  72.       // eslint-disable-next-line no-console
  73.       console.warn('[AUTH] $auth.state is deprecated. Please use $auth.$state or top level props like $auth.loggedIn')
  74.     }
  75.  
  76.     return this.$state
  77.   }
  78.  
  79.   getState (key) {
  80.     if (!this._get_state_warn_shown) {
  81.       this._get_state_warn_shown = true
  82.       // eslint-disable-next-line no-console
  83.       console.warn('[AUTH] $auth.getState is deprecated. Please use $auth.$storage.getState() or top level props like $auth.loggedIn')
  84.     }
  85.  
  86.     return this.$storage.getState(key)
  87.   }
  88.  
  89.   // ---------------------------------------------------------------
  90.   // Strategy and Scheme
  91.   // ---------------------------------------------------------------
  92.  
  93.   get strategy () {
  94.     return this.strategies[this.$state.strategy]
  95.   }
  96.  
  97.   registerStrategy (name, strategy) {
  98.     this.strategies[name] = strategy
  99.   }
  100.  
  101.   setStrategy (name) {
  102.     if (name === this.$storage.getUniversal('strategy')) {
  103.       return Promise.resolve()
  104.     }
  105.  
  106.     // Set strategy
  107.     this.$storage.setUniversal('strategy', name)
  108.  
  109.     // Call mounted hook on active strategy
  110.     return this.mounted()
  111.   }
  112.  
  113.   mounted () {
  114.     if (!this.strategy.mounted) {
  115.       return this.fetchUserOnce()
  116.     }
  117.  
  118.     return Promise.resolve(this.strategy.mounted(...arguments)).catch(error => {
  119.       this.callOnError(error, { method: 'mounted' })
  120.       return Promise.reject(error)
  121.     })
  122.   }
  123.  
  124.   loginWith (name, ...args) {
  125.     return this.setStrategy(name).then(() => this.login(...args))
  126.   }
  127.  
  128.   login () {
  129.     if (!this.strategy.login) {
  130.       return Promise.resolve()
  131.     }
  132.  
  133.     return this.wrapLogin(this.strategy.login(...arguments)).catch(error => {
  134.       this.callOnError(error, { method: 'login' })
  135.       return Promise.reject(error)
  136.     })
  137.   }
  138.  
  139.   fetchUser () {
  140.     if (!this.strategy.fetchUser) {
  141.       return Promise.resolve()
  142.     }
  143.  
  144.     return Promise.resolve(this.strategy.fetchUser(...arguments)).catch(error => {
  145.       this.callOnError(error, { method: 'fetchUser' })
  146.       return Promise.reject(error)
  147.     })
  148.   }
  149.  
  150.   logout () {
  151.     if (!this.strategy.logout) {
  152.       this.reset()
  153.       return Promise.resolve()
  154.     }
  155.  
  156.     return Promise.resolve(this.strategy.logout(...arguments)).catch(error => {
  157.       this.callOnError(error, { method: 'logout' })
  158.       return Promise.reject(error)
  159.     })
  160.   }
  161.  
  162.   setUserToken (token) {
  163.     if (!this.strategy.setUserToken) {
  164.       this.setToken(this.strategy.name, token)
  165.       return Promise.resolve()
  166.     }
  167.  
  168.     return Promise.resolve(this.strategy.setUserToken(token)).catch(error => {
  169.       this.callOnError(error, { method: 'setUserToken' })
  170.       return Promise.reject(error)
  171.     })
  172.   }
  173.  
  174.   reset () {
  175.     if (!this.strategy.reset) {
  176.       this.setUser(false)
  177.       this.setToken(this.$state.strategy, false)
  178.       this.setRefreshToken(this.$state.strategy, false)
  179.       return Promise.resolve()
  180.     }
  181.  
  182.     return Promise.resolve(this.strategy.reset(...arguments)).catch(error => {
  183.       this.callOnError(error, { method: 'reset' })
  184.       return Promise.reject(error)
  185.     })
  186.   }
  187.  
  188.   // ---------------------------------------------------------------
  189.   // Token helpers
  190.   // ---------------------------------------------------------------
  191.  
  192.   getToken (strategy) {
  193.     const _key = this.options.token.prefix + strategy
  194.  
  195.     return this.$storage.getUniversal(_key)
  196.   }
  197.  
  198.   setToken (strategy, token) {
  199.     const _key = this.options.token.prefix + strategy
  200.  
  201.     return this.$storage.setUniversal(_key, token)
  202.   }
  203.  
  204.   syncToken (strategy) {
  205.     const _key = this.options.token.prefix + strategy
  206.  
  207.     return this.$storage.syncUniversal(_key)
  208.   }
  209.  
  210.   // ---------------------------------------------------------------
  211.   // Refresh token helpers
  212.   // ---------------------------------------------------------------
  213.  
  214.   getRefreshToken (strategy) {
  215.     const _key = this.options.refresh_token.prefix + strategy
  216.  
  217.     return this.$storage.getUniversal(_key)
  218.   }
  219.  
  220.   setRefreshToken (strategy, refreshToken) {
  221.     const _key = this.options.refresh_token.prefix + strategy
  222.  
  223.     return this.$storage.setUniversal(_key, refreshToken)
  224.   }
  225.  
  226.   syncRefreshToken (strategy) {
  227.     const _key = this.options.refresh_token.prefix + strategy
  228.  
  229.     return this.$storage.syncUniversal(_key)
  230.   }
  231.  
  232.   // ---------------------------------------------------------------
  233.   // User helpers
  234.   // ---------------------------------------------------------------
  235.  
  236.   get user () {
  237.     return this.$state.user
  238.   }
  239.  
  240.   get loggedIn () {
  241.     return this.$state.loggedIn
  242.   }
  243.  
  244.   fetchUserOnce () {
  245.     if (!this.$state.user) {
  246.       return this.fetchUser(...arguments)
  247.     }
  248.     return Promise.resolve()
  249.   }
  250.  
  251.   setUser (user) {
  252.     this.$storage.setState('user', user)
  253.     this.$storage.setState('loggedIn', Boolean(user))
  254.   }
  255.  
  256.   // ---------------------------------------------------------------
  257.   // Utils
  258.   // ---------------------------------------------------------------
  259.  
  260.   get busy () {
  261.     return this.$storage.getState('busy')
  262.   }
  263.  
  264.   request (endpoint, defaults) {
  265.     const _endpoint =
  266.       typeof defaults === 'object'
  267.         ? Object.assign({}, defaults, endpoint)
  268.         : endpoint
  269.  
  270.     return this.ctx.app.$axios
  271.       .request(_endpoint)
  272.       .then(response => {
  273.         if (_endpoint.propertyName) {
  274.           return getProp(response.data, _endpoint.propertyName)
  275.         } else {
  276.           return response.data
  277.         }
  278.       })
  279.       .catch(error => {
  280.         // Call all error handlers
  281.         this.callOnError(error, { method: 'request' })
  282.  
  283.         // Throw error
  284.         return Promise.reject(error)
  285.       })
  286.   }
  287.  
  288.   requestWith (strategy, endpoint, defaults) {
  289.     const token = this.getToken(strategy)
  290.  
  291.     const _endpoint = Object.assign({}, defaults, endpoint)
  292.  
  293.     const tokenName = this.strategies[strategy].options.tokenName || 'Authorization'
  294.     if (!_endpoint.headers) {
  295.       _endpoint.headers = {}
  296.     }
  297.     if (!_endpoint.headers[tokenName] && isSet(token) && token) {
  298.       _endpoint.headers[tokenName] = token
  299.     }
  300.  
  301.     return this.request(_endpoint)
  302.   }
  303.  
  304.   wrapLogin (promise) {
  305.     this.$storage.setState('busy', true)
  306.     this.error = null
  307.  
  308.     return Promise.resolve(promise)
  309.       .then(() => {
  310.         this.$storage.setState('busy', false)
  311.       })
  312.       .catch(error => {
  313.         this.$storage.setState('busy', false)
  314.         return Promise.reject(error)
  315.       })
  316.   }
  317.  
  318.   onError (listener) {
  319.     this._errorListeners.push(listener)
  320.   }
  321.  
  322.   callOnError (error, payload = {}) {
  323.     this.error = error
  324.  
  325.     for (const fn of this._errorListeners) {
  326.       fn(error, payload)
  327.     }
  328.   }
  329.  
  330.   redirect (name, noRouter = false) {
  331.     if (!this.options.redirect) {
  332.       return
  333.     }
  334.  
  335.     const from = this.options.fullPathRedirect ? this.ctx.route.fullPath : this.ctx.route.path
  336.  
  337.     let to = this.options.redirect[name]
  338.     if (!to) {
  339.       return
  340.     }
  341.  
  342.     // Apply rewrites
  343.     if (this.options.rewriteRedirects) {
  344.       if (name === 'login' && isRelativeURL(from) && !isSameURL(to, from)) {
  345.         this.$storage.setUniversal('redirect', from)
  346.       }
  347.  
  348.       if (name === 'home') {
  349.         const redirect = this.$storage.getUniversal('redirect')
  350.         this.$storage.setUniversal('redirect', null)
  351.  
  352.         if (isRelativeURL(redirect)) {
  353.           to = redirect
  354.         }
  355.       }
  356.     }
  357.  
  358.     // Call onRedirect hook
  359.     to = this.callOnRedirect(to, from) || to
  360.  
  361.     // Prevent infinity redirects
  362.     if (isSameURL(to, from)) {
  363.       return
  364.     }
  365.  
  366.     if (process.client) {
  367.       if (noRouter) {
  368.         window.location.replace(to)
  369.       } else {
  370.         this.ctx.redirect(to, this.ctx.query)
  371.       }
  372.     } else {
  373.       this.ctx.redirect(to, this.ctx.query)
  374.     }
  375.   }
  376.  
  377.   onRedirect (listener) {
  378.     this._redirectListeners.push(listener)
  379.   }
  380.  
  381.   callOnRedirect (to, from) {
  382.     for (const fn of this._redirectListeners) {
  383.       to = fn(to, from) || to
  384.     }
  385.     return to
  386.   }
  387.  
  388.   hasScope (scope) {
  389.     const userScopes = this.$state.user && getProp(this.$state.user, this.options.scopeKey)
  390.  
  391.     if (!userScopes) {
  392.       return undefined
  393.     }
  394.  
  395.     if (Array.isArray(userScopes)) {
  396.       return userScopes.includes(scope)
  397.     }
  398.  
  399.     return Boolean(getProp(userScopes, scope))
  400.   }
  401. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement