'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); var universalUserAgent = require('universal-user-agent'); var request = require('@octokit/request'); var oauthMethods = require('@octokit/oauth-methods'); function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; } function _objectSpread2(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; } function _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; } async function getOAuthAccessToken(state, options) { const cachedAuthentication = getCachedAuthentication(state, options.auth); if (cachedAuthentication) return cachedAuthentication; // Step 1: Request device and user codes // https://docs.github.com/en/developers/apps/authorizing-oauth-apps#step-1-app-requests-the-device-and-user-verification-codes-from-github const { data: verification } = await oauthMethods.createDeviceCode({ clientType: state.clientType, clientId: state.clientId, request: options.request || state.request, // @ts-expect-error the extra code to make TS happy is not worth it scopes: options.auth.scopes || state.scopes }); // Step 2: User must enter the user code on https://github.com/login/device // See https://docs.github.com/en/developers/apps/authorizing-oauth-apps#step-2-prompt-the-user-to-enter-the-user-code-in-a-browser await state.onVerification(verification); // Step 3: Exchange device code for access token // See https://docs.github.com/en/developers/apps/authorizing-oauth-apps#step-3-app-polls-github-to-check-if-the-user-authorized-the-device const authentication = await waitForAccessToken(options.request || state.request, state.clientId, state.clientType, verification); state.authentication = authentication; return authentication; } function getCachedAuthentication(state, auth) { if (auth.refresh === true) return false; if (!state.authentication) return false; if (state.clientType === "github-app") { return state.authentication; } const authentication = state.authentication; const newScope = ("scopes" in auth && auth.scopes || state.scopes).join(" "); const currentScope = authentication.scopes.join(" "); return newScope === currentScope ? authentication : false; } async function wait(seconds) { await new Promise(resolve => setTimeout(resolve, seconds * 1000)); } async function waitForAccessToken(request, clientId, clientType, verification) { try { const options = { clientId, request, code: verification.device_code }; // WHY TYPESCRIPT WHY ARE YOU DOING THIS TO ME const { authentication } = clientType === "oauth-app" ? await oauthMethods.exchangeDeviceCode(_objectSpread2(_objectSpread2({}, options), {}, { clientType: "oauth-app" })) : await oauthMethods.exchangeDeviceCode(_objectSpread2(_objectSpread2({}, options), {}, { clientType: "github-app" })); return _objectSpread2({ type: "token", tokenType: "oauth" }, authentication); } catch (error) { // istanbul ignore if if (!error.response) throw error; const errorType = error.response.data.error; if (errorType === "authorization_pending") { await wait(verification.interval); return waitForAccessToken(request, clientId, clientType, verification); } if (errorType === "slow_down") { await wait(verification.interval + 5); return waitForAccessToken(request, clientId, clientType, verification); } throw error; } } async function auth(state, authOptions) { return getOAuthAccessToken(state, { auth: authOptions }); } async function hook(state, request, route, parameters) { let endpoint = request.endpoint.merge(route, parameters); // Do not intercept request to retrieve codes or token if (/\/login\/(oauth\/access_token|device\/code)$/.test(endpoint.url)) { return request(endpoint); } const { token } = await getOAuthAccessToken(state, { request, auth: { type: "oauth" } }); endpoint.headers.authorization = `token ${token}`; return request(endpoint); } const VERSION = "3.1.1"; function createOAuthDeviceAuth(options) { const requestWithDefaults = options.request || request.request.defaults({ headers: { "user-agent": `octokit-auth-oauth-device.js/${VERSION} ${universalUserAgent.getUserAgent()}` } }); const { request: request$1 = requestWithDefaults } = options, otherOptions = _objectWithoutProperties(options, ["request"]); const state = options.clientType === "github-app" ? _objectSpread2(_objectSpread2({}, otherOptions), {}, { clientType: "github-app", request: request$1 }) : _objectSpread2(_objectSpread2({}, otherOptions), {}, { clientType: "oauth-app", request: request$1, scopes: options.scopes || [] }); if (!options.clientId) { throw new Error('[@octokit/auth-oauth-device] "clientId" option must be set (https://github.com/octokit/auth-oauth-device.js#usage)'); } if (!options.onVerification) { throw new Error('[@octokit/auth-oauth-device] "onVerification" option must be a function (https://github.com/octokit/auth-oauth-device.js#usage)'); } // @ts-ignore too much for tsc / ts-jest ¯\_(ツ)_/¯ return Object.assign(auth.bind(null, state), { hook: hook.bind(null, state) }); } exports.createOAuthDeviceAuth = createOAuthDeviceAuth; //# sourceMappingURL=index.js.map