|
|
"use strict"; |
|
|
|
|
|
Object.defineProperty(exports, "__esModule", { |
|
|
value: true |
|
|
}); |
|
|
exports["default"] = undefined; |
|
|
|
|
|
var _utils = require("./utils.js"); |
|
|
|
|
|
var _response = require("./response.js"); |
|
|
|
|
|
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } |
|
|
|
|
|
function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } |
|
|
|
|
|
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; } |
|
|
|
|
|
var fetch; |
|
|
var crypto; |
|
|
var Encoder; |
|
|
|
|
|
var TokenExpirationBuffer = 300 * 1000; |
|
|
var PKCELength = 128; |
|
|
var TokenAccessTypes = ['legacy', 'offline', 'online']; |
|
|
var GrantTypes = ['code', 'token']; |
|
|
var IncludeGrantedScopes = ['none', 'user', 'team']; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var DropboxAuth = function () { |
|
|
function DropboxAuth(options) { |
|
|
_classCallCheck(this, DropboxAuth); |
|
|
|
|
|
options = options || {}; |
|
|
|
|
|
if ((0, _utils.isBrowserEnv)()) { |
|
|
fetch = window.fetch.bind(window); |
|
|
crypto = window.crypto || window.msCrypto; |
|
|
} else if ((0, _utils.isWorkerEnv)()) { |
|
|
|
|
|
fetch = self.fetch.bind(self); |
|
|
crypto = self.crypto; |
|
|
|
|
|
} else { |
|
|
fetch = require('node-fetch'); |
|
|
|
|
|
crypto = require('crypto'); |
|
|
} |
|
|
|
|
|
if (typeof TextEncoder === 'undefined') { |
|
|
Encoder = require('util').TextEncoder; |
|
|
} else { |
|
|
Encoder = TextEncoder; |
|
|
} |
|
|
|
|
|
this.fetch = options.fetch || fetch; |
|
|
this.accessToken = options.accessToken; |
|
|
this.accessTokenExpiresAt = options.accessTokenExpiresAt; |
|
|
this.refreshToken = options.refreshToken; |
|
|
this.clientId = options.clientId; |
|
|
this.clientSecret = options.clientSecret; |
|
|
this.domain = options.domain; |
|
|
this.domainDelimiter = options.domainDelimiter; |
|
|
this.customHeaders = options.customHeaders; |
|
|
this.dataOnBody = options.dataOnBody; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
_createClass(DropboxAuth, [{ |
|
|
key: "setAccessToken", |
|
|
value: function setAccessToken(accessToken) { |
|
|
this.accessToken = accessToken; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}, { |
|
|
key: "getAccessToken", |
|
|
value: function getAccessToken() { |
|
|
return this.accessToken; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}, { |
|
|
key: "setClientId", |
|
|
value: function setClientId(clientId) { |
|
|
this.clientId = clientId; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}, { |
|
|
key: "getClientId", |
|
|
value: function getClientId() { |
|
|
return this.clientId; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}, { |
|
|
key: "setClientSecret", |
|
|
value: function setClientSecret(clientSecret) { |
|
|
this.clientSecret = clientSecret; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}, { |
|
|
key: "getClientSecret", |
|
|
value: function getClientSecret() { |
|
|
return this.clientSecret; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}, { |
|
|
key: "getRefreshToken", |
|
|
value: function getRefreshToken() { |
|
|
return this.refreshToken; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}, { |
|
|
key: "setRefreshToken", |
|
|
value: function setRefreshToken(refreshToken) { |
|
|
this.refreshToken = refreshToken; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}, { |
|
|
key: "getAccessTokenExpiresAt", |
|
|
value: function getAccessTokenExpiresAt() { |
|
|
return this.accessTokenExpiresAt; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}, { |
|
|
key: "setAccessTokenExpiresAt", |
|
|
value: function setAccessTokenExpiresAt(accessTokenExpiresAt) { |
|
|
this.accessTokenExpiresAt = accessTokenExpiresAt; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}, { |
|
|
key: "setCodeVerifier", |
|
|
value: function setCodeVerifier(codeVerifier) { |
|
|
this.codeVerifier = codeVerifier; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}, { |
|
|
key: "getCodeVerifier", |
|
|
value: function getCodeVerifier() { |
|
|
return this.codeVerifier; |
|
|
} |
|
|
}, { |
|
|
key: "generateCodeChallenge", |
|
|
value: function generateCodeChallenge() { |
|
|
var _this = this; |
|
|
|
|
|
var encoder = new Encoder(); |
|
|
var codeData = encoder.encode(this.codeVerifier); |
|
|
var codeChallenge; |
|
|
|
|
|
if ((0, _utils.isBrowserEnv)() || (0, _utils.isWorkerEnv)()) { |
|
|
return crypto.subtle.digest('SHA-256', codeData).then(function (digestedHash) { |
|
|
var base64String = btoa(String.fromCharCode.apply(null, new Uint8Array(digestedHash))); |
|
|
codeChallenge = (0, _utils.createBrowserSafeString)(base64String).substr(0, 128); |
|
|
_this.codeChallenge = codeChallenge; |
|
|
}); |
|
|
} |
|
|
|
|
|
var digestedHash = crypto.createHash('sha256').update(codeData).digest(); |
|
|
codeChallenge = (0, _utils.createBrowserSafeString)(digestedHash); |
|
|
this.codeChallenge = codeChallenge; |
|
|
return Promise.resolve(); |
|
|
} |
|
|
}, { |
|
|
key: "generatePKCECodes", |
|
|
value: function generatePKCECodes() { |
|
|
var codeVerifier; |
|
|
|
|
|
if ((0, _utils.isBrowserEnv)() || (0, _utils.isWorkerEnv)()) { |
|
|
var array = new Uint8Array(PKCELength); |
|
|
var randomValueArray = crypto.getRandomValues(array); |
|
|
var base64String = btoa(randomValueArray); |
|
|
codeVerifier = (0, _utils.createBrowserSafeString)(base64String).substr(0, 128); |
|
|
} else { |
|
|
var randomBytes = crypto.randomBytes(PKCELength); |
|
|
codeVerifier = (0, _utils.createBrowserSafeString)(randomBytes).substr(0, 128); |
|
|
} |
|
|
|
|
|
this.codeVerifier = codeVerifier; |
|
|
return this.generateCodeChallenge(); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}, { |
|
|
key: "getAuthenticationUrl", |
|
|
value: function getAuthenticationUrl(redirectUri, state) { |
|
|
var _this2 = this; |
|
|
|
|
|
var authType = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 'token'; |
|
|
var tokenAccessType = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : null; |
|
|
var scope = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : null; |
|
|
var includeGrantedScopes = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : 'none'; |
|
|
var usePKCE = arguments.length > 6 && arguments[6] !== undefined ? arguments[6] : false; |
|
|
var clientId = this.getClientId(); |
|
|
var baseUrl = (0, _utils.OAuth2AuthorizationUrl)(this.domain); |
|
|
|
|
|
if (!clientId) { |
|
|
throw new Error('A client id is required. You can set the client id using .setClientId().'); |
|
|
} |
|
|
|
|
|
if (authType !== 'code' && !redirectUri) { |
|
|
throw new Error('A redirect uri is required.'); |
|
|
} |
|
|
|
|
|
if (!GrantTypes.includes(authType)) { |
|
|
throw new Error('Authorization type must be code or token'); |
|
|
} |
|
|
|
|
|
if (tokenAccessType && !TokenAccessTypes.includes(tokenAccessType)) { |
|
|
throw new Error('Token Access Type must be legacy, offline, or online'); |
|
|
} |
|
|
|
|
|
if (scope && !(scope instanceof Array)) { |
|
|
throw new Error('Scope must be an array of strings'); |
|
|
} |
|
|
|
|
|
if (!IncludeGrantedScopes.includes(includeGrantedScopes)) { |
|
|
throw new Error('includeGrantedScopes must be none, user, or team'); |
|
|
} |
|
|
|
|
|
var authUrl; |
|
|
|
|
|
if (authType === 'code') { |
|
|
authUrl = "".concat(baseUrl, "?response_type=code&client_id=").concat(clientId); |
|
|
} else { |
|
|
authUrl = "".concat(baseUrl, "?response_type=token&client_id=").concat(clientId); |
|
|
} |
|
|
|
|
|
if (redirectUri) { |
|
|
authUrl += "&redirect_uri=".concat(redirectUri); |
|
|
} |
|
|
|
|
|
if (state) { |
|
|
authUrl += "&state=".concat(state); |
|
|
} |
|
|
|
|
|
if (tokenAccessType) { |
|
|
authUrl += "&token_access_type=".concat(tokenAccessType); |
|
|
} |
|
|
|
|
|
if (scope) { |
|
|
authUrl += "&scope=".concat(scope.join(' ')); |
|
|
} |
|
|
|
|
|
if (includeGrantedScopes !== 'none') { |
|
|
authUrl += "&include_granted_scopes=".concat(includeGrantedScopes); |
|
|
} |
|
|
|
|
|
if (usePKCE) { |
|
|
return this.generatePKCECodes().then(function () { |
|
|
authUrl += '&code_challenge_method=S256'; |
|
|
authUrl += "&code_challenge=".concat(_this2.codeChallenge); |
|
|
return authUrl; |
|
|
}); |
|
|
} |
|
|
|
|
|
return Promise.resolve(authUrl); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}, { |
|
|
key: "getAccessTokenFromCode", |
|
|
value: function getAccessTokenFromCode(redirectUri, code) { |
|
|
var clientId = this.getClientId(); |
|
|
var clientSecret = this.getClientSecret(); |
|
|
|
|
|
if (!clientId) { |
|
|
throw new Error('A client id is required. You can set the client id using .setClientId().'); |
|
|
} |
|
|
|
|
|
var path = (0, _utils.OAuth2TokenUrl)(this.domain, this.domainDelimiter); |
|
|
path += '?grant_type=authorization_code'; |
|
|
path += "&code=".concat(code); |
|
|
path += "&client_id=".concat(clientId); |
|
|
|
|
|
if (clientSecret) { |
|
|
path += "&client_secret=".concat(clientSecret); |
|
|
} else { |
|
|
if (!this.codeVerifier) { |
|
|
throw new Error('You must use PKCE when generating the authorization URL to not include a client secret'); |
|
|
} |
|
|
|
|
|
path += "&code_verifier=".concat(this.codeVerifier); |
|
|
} |
|
|
|
|
|
if (redirectUri) { |
|
|
path += "&redirect_uri=".concat(redirectUri); |
|
|
} |
|
|
|
|
|
var fetchOptions = { |
|
|
method: 'POST', |
|
|
headers: { |
|
|
'Content-Type': 'application/x-www-form-urlencoded' |
|
|
} |
|
|
}; |
|
|
return this.fetch(path, fetchOptions).then(function (res) { |
|
|
return (0, _response.parseResponse)(res); |
|
|
}); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}, { |
|
|
key: "checkAndRefreshAccessToken", |
|
|
value: function checkAndRefreshAccessToken() { |
|
|
var canRefresh = this.getRefreshToken() && this.getClientId(); |
|
|
var needsRefresh = !this.getAccessTokenExpiresAt() || new Date(Date.now() + TokenExpirationBuffer) >= this.getAccessTokenExpiresAt(); |
|
|
var needsToken = !this.getAccessToken(); |
|
|
|
|
|
if ((needsRefresh || needsToken) && canRefresh) { |
|
|
return this.refreshAccessToken(); |
|
|
} |
|
|
|
|
|
return Promise.resolve(); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}, { |
|
|
key: "refreshAccessToken", |
|
|
value: function refreshAccessToken() { |
|
|
var _this3 = this; |
|
|
|
|
|
var scope = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null; |
|
|
var clientId = this.getClientId(); |
|
|
var clientSecret = this.getClientSecret(); |
|
|
|
|
|
if (!clientId) { |
|
|
throw new Error('A client id is required. You can set the client id using .setClientId().'); |
|
|
} |
|
|
|
|
|
if (scope && !(scope instanceof Array)) { |
|
|
throw new Error('Scope must be an array of strings'); |
|
|
} |
|
|
|
|
|
var refreshUrl = (0, _utils.OAuth2TokenUrl)(this.domain, this.domainDelimiter); |
|
|
var fetchOptions = { |
|
|
headers: { |
|
|
'Content-Type': 'application/json' |
|
|
}, |
|
|
method: 'POST' |
|
|
}; |
|
|
|
|
|
if (this.dataOnBody) { |
|
|
var body = { |
|
|
grant_type: 'refresh_token', |
|
|
client_id: clientId, |
|
|
refresh_token: this.getRefreshToken() |
|
|
}; |
|
|
|
|
|
if (clientSecret) { |
|
|
body.client_secret = clientSecret; |
|
|
} |
|
|
|
|
|
if (scope) { |
|
|
body.scope = scope.join(' '); |
|
|
} |
|
|
|
|
|
fetchOptions.body = body; |
|
|
} else { |
|
|
refreshUrl += "?grant_type=refresh_token&refresh_token=".concat(this.getRefreshToken()); |
|
|
refreshUrl += "&client_id=".concat(clientId); |
|
|
|
|
|
if (clientSecret) { |
|
|
refreshUrl += "&client_secret=".concat(clientSecret); |
|
|
} |
|
|
|
|
|
if (scope) { |
|
|
refreshUrl += "&scope=".concat(scope.join(' ')); |
|
|
} |
|
|
} |
|
|
|
|
|
return this.fetch(refreshUrl, fetchOptions).then(function (res) { |
|
|
return (0, _response.parseResponse)(res); |
|
|
}).then(function (res) { |
|
|
_this3.setAccessToken(res.result.access_token); |
|
|
|
|
|
_this3.setAccessTokenExpiresAt((0, _utils.getTokenExpiresAtDate)(res.result.expires_in)); |
|
|
}); |
|
|
} |
|
|
}]); |
|
|
|
|
|
return DropboxAuth; |
|
|
}(); |
|
|
|
|
|
exports["default"] = DropboxAuth; |