2018-10-29 23:23:46 +00:00
/* global XMLHttpRequest FormData */
2018-11-06 01:16:54 +00:00
'use strict' ;
2018-10-29 23:23:46 +00:00
2018-11-06 01:16:54 +00:00
let ajaxcfg = { } ;
2018-10-29 23:23:46 +00:00
class AjaxError extends Error {
constructor ( reason , data , xhr ) {
2018-11-06 01:16:54 +00:00
super ( reason ) ;
this . data = data ;
this . xhr = xhr ;
2018-10-29 23:23:46 +00:00
}
}
export default class Ajax {
static async get ( opts ) {
2018-11-06 01:16:54 +00:00
if ( ! opts ) { opts = { } ; }
opts . method = 'get' ;
return Ajax . ajax ( opts ) ;
2018-10-29 23:23:46 +00:00
}
static async post ( opts ) {
2018-11-06 01:16:54 +00:00
if ( ! opts ) { opts = { } ; }
opts . method = 'post' ;
return Ajax . ajax ( opts ) ;
2018-10-29 23:23:46 +00:00
}
static async put ( opts ) {
2018-11-06 01:16:54 +00:00
if ( ! opts ) { opts = { } ; }
opts . method = 'put' ;
return Ajax . ajax ( opts ) ;
2018-10-29 23:23:46 +00:00
}
static async patch ( opts ) {
2018-11-06 01:16:54 +00:00
if ( ! opts ) { opts = { } ; }
opts . method = 'patch' ;
return Ajax . ajax ( opts ) ;
2018-10-29 23:23:46 +00:00
}
static async delete ( opts ) {
2018-11-06 01:16:54 +00:00
if ( ! opts ) { opts = { } ; }
opts . method = 'delete' ;
return Ajax . ajax ( opts ) ;
2018-10-29 23:23:46 +00:00
}
static async head ( opts ) {
2018-11-06 01:16:54 +00:00
if ( ! opts ) { opts = { } ; }
opts . method = 'head' ;
return Ajax . ajax ( opts ) ;
2018-10-29 23:23:46 +00:00
}
static async options ( opts ) {
2018-11-06 01:16:54 +00:00
if ( ! opts ) { opts = { } ; }
opts . method = 'options' ;
return Ajax . ajax ( opts ) ;
2018-10-29 23:23:46 +00:00
}
static ajax ( opts ) {
return new Promise ( ( resolve , reject ) => {
2018-11-06 01:16:54 +00:00
if ( ! opts ) { reject ( new Error ( 'Missing required options parameter.' ) ) ; }
2018-10-29 23:23:46 +00:00
if ( opts . method ) {
2018-11-06 01:16:54 +00:00
if ( ! [ 'get' , 'post' , 'put' , 'patch' , 'delete' , 'head' , 'options' ] . includes ( opts . method . toLowerCase ( ) ) ) { reject ( new Error ( 'opts.method must be one of: GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS.' ) ) ; }
opts . method = opts . method . toUpperCase ( ) ;
2018-10-29 23:23:46 +00:00
}
2018-11-06 01:16:54 +00:00
var xhr = opts . xhr || new XMLHttpRequest ( ) ;
2018-10-29 23:23:46 +00:00
2018-11-06 01:16:54 +00:00
var fd = null ;
var qs = '' ;
2018-10-29 23:23:46 +00:00
if ( opts . data && opts . method . toLowerCase ( ) !== 'get' ) {
2018-11-06 01:16:54 +00:00
fd = new FormData ( ) ;
2018-10-29 23:23:46 +00:00
for ( let key in opts . data ) {
2018-11-06 01:16:54 +00:00
fd . append ( key , opts . data [ key ] ) ;
2018-10-29 23:23:46 +00:00
}
} else if ( opts . data ) {
2018-11-06 01:16:54 +00:00
qs += '?' ;
let params = [ ] ;
2018-10-29 23:23:46 +00:00
for ( let key in opts . data ) {
2018-11-06 01:16:54 +00:00
params . push ( [ key , opts . data [ key ] ] . join ( '=' ) ) ;
2018-10-29 23:23:46 +00:00
}
2018-11-06 01:16:54 +00:00
qs += params . join ( '&' ) ;
2018-10-29 23:23:46 +00:00
}
xhr . onload = ( ) => {
2018-11-06 01:16:54 +00:00
if ( xhr . status !== 200 ) { return xhr . onerror ( ) ; }
var data = xhr . response ;
2018-10-29 23:23:46 +00:00
resolve ( {
data ,
xhr
2018-11-06 01:16:54 +00:00
} ) ;
} ;
2018-10-29 23:23:46 +00:00
xhr . onerror = ( ) => {
2018-11-06 01:16:54 +00:00
var data = xhr . response ;
2018-10-29 23:23:46 +00:00
// method not allowed
if ( xhr . status === 405 ) {
2018-11-06 01:16:54 +00:00
reject ( new AjaxError ( '405 Method Not Allowed' , data , xhr ) ) ;
return ;
2018-10-29 23:35:27 +00:00
} else if ( xhr . status === 404 ) {
2018-11-06 01:16:54 +00:00
reject ( new AjaxError ( '404 Not Found' , data , xhr ) ) ;
return ;
2018-10-29 23:23:46 +00:00
}
try {
// if the access token is invalid, try to use the refresh token
2018-11-06 01:16:54 +00:00
var json = JSON . parse ( data ) ;
2018-10-29 23:23:46 +00:00
if ( json . error === 'access_denied' && json . hint . includes ( 'token' ) && json . hint . includes ( 'invalid' ) && ajaxcfg . refresh _token ) {
2018-11-06 01:16:54 +00:00
return Ajax . refresh ( opts ) ;
2018-10-29 23:23:46 +00:00
} else if ( json . error === 'access_denied' && json . hint . includes ( 'token' ) && json . hint . includes ( 'revoked' ) ) {
2018-11-06 01:16:54 +00:00
reject ( new AjaxError ( 'token revoked' , data , xhr ) ) ;
2018-10-29 23:23:46 +00:00
}
} catch ( e ) {
2018-11-06 01:16:54 +00:00
reject ( new AjaxError ( e . toString ( ) , data , xhr ) ) ;
2018-10-29 23:23:46 +00:00
} finally {
2018-11-06 01:16:54 +00:00
reject ( new AjaxError ( data , xhr . status , xhr ) ) ;
2018-10-29 23:23:46 +00:00
}
2018-11-06 01:16:54 +00:00
} ;
2018-10-29 23:23:46 +00:00
2018-11-06 01:16:54 +00:00
xhr . open ( opts . method || 'GET' , opts . url + qs || window . location . href ) ;
2018-10-29 23:23:46 +00:00
if ( opts . headers ) {
2018-11-06 01:16:54 +00:00
for ( let key in opts . headers ) { xhr . setRequestHeader ( key , opts . headers [ key ] ) ; }
2018-10-29 23:23:46 +00:00
}
2018-11-06 01:16:54 +00:00
if ( ajaxcfg . access _token && ! ( opts . headers || { } ) . Authorization ) { xhr . setRequestHeader ( 'Authorization' , 'Bearer ' + ajaxcfg . access _token ) ; }
xhr . send ( fd ) ;
} ) ;
2018-10-29 23:23:46 +00:00
}
static refresh ( opts ) {
return new Promise ( ( resolve , reject ) => {
2018-11-06 01:16:54 +00:00
var xhr = new XMLHttpRequest ( ) ;
2018-10-29 23:23:46 +00:00
2018-11-06 01:16:54 +00:00
var fd = new FormData ( ) ;
2018-10-29 23:23:46 +00:00
const OAUTH _TOKEN _REQUEST = {
grant _type : 'refresh_token' ,
refresh _token : ajaxcfg . refresh _token ,
client _id : 'foxfile' ,
client _secret : 1
2018-11-06 01:16:54 +00:00
} ;
2018-10-29 23:23:46 +00:00
for ( var key in OAUTH _TOKEN _REQUEST ) {
2018-11-06 01:16:54 +00:00
fd . append ( key , OAUTH _TOKEN _REQUEST [ key ] ) ;
2018-10-29 23:23:46 +00:00
}
// try original request
xhr . onload = ( ) => {
2018-11-06 01:16:54 +00:00
if ( xhr . status !== 200 ) { return xhr . onerror ( ) ; }
if ( ajaxcfg . refresh ) { ajaxcfg . refresh ( xhr . response ) ; }
var json = JSON . parse ( xhr . response ) ;
ajaxcfg . access _token = json . access _token ;
ajaxcfg . refresh _token = json . refresh _token ;
return Ajax . ajax ( opts ) ;
} ;
2018-10-29 23:23:46 +00:00
// if this fails, dont try again
xhr . onerror = ( ) => {
2018-11-06 01:16:54 +00:00
var data = xhr . response ;
reject ( new AjaxError ( xhr . status , data , xhr ) ) ;
} ;
xhr . open ( 'POST' , ajaxcfg . refresh _url ) ;
xhr . send ( fd ) ;
} ) ;
2018-10-29 23:23:46 +00:00
}
static setTokenData ( tokens ) {
2018-11-06 01:16:54 +00:00
if ( ! tokens ) { throw new Error ( 'Missing tokens.' ) ; }
if ( ! tokens . access _token && ! tokens . refresh _token && ! tokens . refresh _url ) { throw new Error ( 'Missing at least one of: access_token, refresh_token, refresh_url.' ) ; }
if ( tokens . access _token ) { ajaxcfg . access _token = tokens . access _token ; }
if ( tokens . refresh _token ) { ajaxcfg . refresh _token = tokens . refresh _token ; }
if ( tokens . refresh _url ) { ajaxcfg . refresh _url = tokens . refresh _url ; }
return true ;
2018-10-29 23:23:46 +00:00
}
static onRefresh ( func ) {
2018-11-06 01:16:54 +00:00
ajaxcfg . refresh = func ;
2018-10-29 23:23:46 +00:00
}
}