// pkg/dist-src/index.js import { getUserAgent } from "universal-user-agent"; import { request as defaultRequest } from "@octokit/request"; import { createOAuthAppAuth } from "@octokit/auth-oauth-app"; // pkg/dist-src/get-app-authentication.js import githubAppJwt from "universal-github-app-jwt"; async function getAppAuthentication({ appId, privateKey, timeDifference }) { try { const authOptions = { id: appId, privateKey }; if (timeDifference) { Object.assign(authOptions, { now: Math.floor(Date.now() / 1e3) + timeDifference }); } const appAuthentication = await githubAppJwt(authOptions); return { type: "app", token: appAuthentication.token, appId: appAuthentication.appId, expiresAt: new Date(appAuthentication.expiration * 1e3).toISOString() }; } catch (error) { if (privateKey === "-----BEGIN RSA PRIVATE KEY-----") { throw new Error( "The 'privateKey` option contains only the first line '-----BEGIN RSA PRIVATE KEY-----'. If you are setting it using a `.env` file, make sure it is set on a single line with newlines replaced by '\n'" ); } else { throw error; } } } // pkg/dist-src/cache.js import { Lru } from "toad-cache"; function getCache() { return new Lru( // cache max. 15000 tokens, that will use less than 10mb memory 15e3, // Cache for 1 minute less than GitHub expiry 1e3 * 60 * 59 ); } async function get(cache, options) { const cacheKey = optionsToCacheKey(options); const result = await cache.get(cacheKey); if (!result) { return; } const [ token, createdAt, expiresAt, repositorySelection, permissionsString, singleFileName ] = result.split("|"); const permissions = options.permissions || permissionsString.split(/,/).reduce((permissions2, string) => { if (/!$/.test(string)) { permissions2[string.slice(0, -1)] = "write"; } else { permissions2[string] = "read"; } return permissions2; }, {}); return { token, createdAt, expiresAt, permissions, repositoryIds: options.repositoryIds, repositoryNames: options.repositoryNames, singleFileName, repositorySelection }; } async function set(cache, options, data) { const key = optionsToCacheKey(options); const permissionsString = options.permissions ? "" : Object.keys(data.permissions).map( (name) => `${name}${data.permissions[name] === "write" ? "!" : ""}` ).join(","); const value = [ data.token, data.createdAt, data.expiresAt, data.repositorySelection, permissionsString, data.singleFileName ].join("|"); await cache.set(key, value); } function optionsToCacheKey({ installationId, permissions = {}, repositoryIds = [], repositoryNames = [] }) { const permissionsString = Object.keys(permissions).sort().map((name) => permissions[name] === "read" ? name : `${name}!`).join(","); const repositoryIdsString = repositoryIds.sort().join(","); const repositoryNamesString = repositoryNames.join(","); return [ installationId, repositoryIdsString, repositoryNamesString, permissionsString ].filter(Boolean).join("|"); } // pkg/dist-src/to-token-authentication.js function toTokenAuthentication({ installationId, token, createdAt, expiresAt, repositorySelection, permissions, repositoryIds, repositoryNames, singleFileName }) { return Object.assign( { type: "token", tokenType: "installation", token, installationId, permissions, createdAt, expiresAt, repositorySelection }, repositoryIds ? { repositoryIds } : null, repositoryNames ? { repositoryNames } : null, singleFileName ? { singleFileName } : null ); } // pkg/dist-src/get-installation-authentication.js async function getInstallationAuthentication(state, options, customRequest) { const installationId = Number(options.installationId || state.installationId); if (!installationId) { throw new Error( "[@octokit/auth-app] installationId option is required for installation authentication." ); } if (options.factory) { const { type, factory, oauthApp, ...factoryAuthOptions } = { ...state, ...options }; return factory(factoryAuthOptions); } const optionsWithInstallationTokenFromState = Object.assign( { installationId }, options ); if (!options.refresh) { const result = await get( state.cache, optionsWithInstallationTokenFromState ); if (result) { const { token: token2, createdAt: createdAt2, expiresAt: expiresAt2, permissions: permissions2, repositoryIds: repositoryIds2, repositoryNames: repositoryNames2, singleFileName: singleFileName2, repositorySelection: repositorySelection2 } = result; return toTokenAuthentication({ installationId, token: token2, createdAt: createdAt2, expiresAt: expiresAt2, permissions: permissions2, repositorySelection: repositorySelection2, repositoryIds: repositoryIds2, repositoryNames: repositoryNames2, singleFileName: singleFileName2 }); } } const appAuthentication = await getAppAuthentication(state); const request = customRequest || state.request; const payload = { installation_id: installationId, mediaType: { previews: ["machine-man"] }, headers: { authorization: `bearer ${appAuthentication.token}` } }; if (options.repositoryIds) { Object.assign(payload, { repository_ids: options.repositoryIds }); } if (options.repositoryNames) { Object.assign(payload, { repositories: options.repositoryNames }); } if (options.permissions) { Object.assign(payload, { permissions: options.permissions }); } const { data: { token, expires_at: expiresAt, repositories, permissions: permissionsOptional, repository_selection: repositorySelectionOptional, single_file: singleFileName } } = await request( "POST /app/installations/{installation_id}/access_tokens", payload ); const permissions = permissionsOptional || {}; const repositorySelection = repositorySelectionOptional || "all"; const repositoryIds = repositories ? repositories.map((r) => r.id) : void 0; const repositoryNames = repositories ? repositories.map((repo) => repo.name) : void 0; const createdAt = (/* @__PURE__ */ new Date()).toISOString(); const cacheOptions = { token, createdAt, expiresAt, repositorySelection, permissions, repositoryIds, repositoryNames }; if (singleFileName) { Object.assign(payload, { singleFileName }); } await set(state.cache, optionsWithInstallationTokenFromState, cacheOptions); const cacheData = { installationId, token, createdAt, expiresAt, repositorySelection, permissions, repositoryIds, repositoryNames }; if (singleFileName) { Object.assign(cacheData, { singleFileName }); } return toTokenAuthentication(cacheData); } // pkg/dist-src/auth.js async function auth(state, authOptions) { switch (authOptions.type) { case "app": return getAppAuthentication(state); case "oauth-app": return state.oauthApp({ type: "oauth-app" }); case "installation": authOptions; return getInstallationAuthentication(state, { ...authOptions, type: "installation" }); case "oauth-user": return state.oauthApp(authOptions); default: throw new Error(`Invalid auth type: ${authOptions.type}`); } } // pkg/dist-src/hook.js import { requiresBasicAuth } from "@octokit/auth-oauth-user"; import { RequestError } from "@octokit/request-error"; // pkg/dist-src/requires-app-auth.js var PATHS = [ "/app", "/app/hook/config", "/app/hook/deliveries", "/app/hook/deliveries/{delivery_id}", "/app/hook/deliveries/{delivery_id}/attempts", "/app/installations", "/app/installations/{installation_id}", "/app/installations/{installation_id}/access_tokens", "/app/installations/{installation_id}/suspended", "/app/installation-requests", "/marketplace_listing/accounts/{account_id}", "/marketplace_listing/plan", "/marketplace_listing/plans", "/marketplace_listing/plans/{plan_id}/accounts", "/marketplace_listing/stubbed/accounts/{account_id}", "/marketplace_listing/stubbed/plan", "/marketplace_listing/stubbed/plans", "/marketplace_listing/stubbed/plans/{plan_id}/accounts", "/orgs/{org}/installation", "/repos/{owner}/{repo}/installation", "/users/{username}/installation" ]; function routeMatcher(paths) { const regexes = paths.map( (p) => p.split("/").map((c) => c.startsWith("{") ? "(?:.+?)" : c).join("/") ); const regex = `^(?:${regexes.map((r) => `(?:${r})`).join("|")})$`; return new RegExp(regex, "i"); } var REGEX = routeMatcher(PATHS); function requiresAppAuth(url) { return !!url && REGEX.test(url.split("?")[0]); } // pkg/dist-src/hook.js var FIVE_SECONDS_IN_MS = 5 * 1e3; function isNotTimeSkewError(error) { return !(error.message.match( /'Expiration time' claim \('exp'\) must be a numeric value representing the future time at which the assertion expires/ ) || error.message.match( /'Issued at' claim \('iat'\) must be an Integer representing the time that the assertion was issued/ )); } async function hook(state, request, route, parameters) { const endpoint = request.endpoint.merge(route, parameters); const url = endpoint.url; if (/\/login\/oauth\/access_token$/.test(url)) { return request(endpoint); } if (requiresAppAuth(url.replace(request.endpoint.DEFAULTS.baseUrl, ""))) { const { token: token2 } = await getAppAuthentication(state); endpoint.headers.authorization = `bearer ${token2}`; let response; try { response = await request(endpoint); } catch (error) { if (isNotTimeSkewError(error)) { throw error; } if (typeof error.response.headers.date === "undefined") { throw error; } const diff = Math.floor( (Date.parse(error.response.headers.date) - Date.parse((/* @__PURE__ */ new Date()).toString())) / 1e3 ); state.log.warn(error.message); state.log.warn( `[@octokit/auth-app] GitHub API time and system time are different by ${diff} seconds. Retrying request with the difference accounted for.` ); const { token: token3 } = await getAppAuthentication({ ...state, timeDifference: diff }); endpoint.headers.authorization = `bearer ${token3}`; return request(endpoint); } return response; } if (requiresBasicAuth(url)) { const authentication = await state.oauthApp({ type: "oauth-app" }); endpoint.headers.authorization = authentication.headers.authorization; return request(endpoint); } const { token, createdAt } = await getInstallationAuthentication( state, // @ts-expect-error TBD {}, request.defaults({ baseUrl: endpoint.baseUrl }) ); endpoint.headers.authorization = `token ${token}`; return sendRequestWithRetries( state, request, endpoint, createdAt ); } async function sendRequestWithRetries(state, request, options, createdAt, retries = 0) { const timeSinceTokenCreationInMs = +/* @__PURE__ */ new Date() - +new Date(createdAt); try { return await request(options); } catch (error) { if (error.status !== 401) { throw error; } if (timeSinceTokenCreationInMs >= FIVE_SECONDS_IN_MS) { if (retries > 0) { error.message = `After ${retries} retries within ${timeSinceTokenCreationInMs / 1e3}s of creating the installation access token, the response remains 401. At this point, the cause may be an authentication problem or a system outage. Please check https://www.githubstatus.com for status information`; } throw error; } ++retries; const awaitTime = retries * 1e3; state.log.warn( `[@octokit/auth-app] Retrying after 401 response to account for token replication delay (retry: ${retries}, wait: ${awaitTime / 1e3}s)` ); await new Promise((resolve) => setTimeout(resolve, awaitTime)); return sendRequestWithRetries(state, request, options, createdAt, retries); } } // pkg/dist-src/version.js var VERSION = "7.1.5"; // pkg/dist-src/index.js import { createOAuthUserAuth } from "@octokit/auth-oauth-user"; function createAppAuth(options) { if (!options.appId) { throw new Error("[@octokit/auth-app] appId option is required"); } if (!options.privateKey) { throw new Error("[@octokit/auth-app] privateKey option is required"); } if ("installationId" in options && !options.installationId) { throw new Error( "[@octokit/auth-app] installationId is set to a falsy value" ); } const log = Object.assign( { warn: console.warn.bind(console) }, options.log ); const request = options.request || defaultRequest.defaults({ headers: { "user-agent": `octokit-auth-app.js/${VERSION} ${getUserAgent()}` } }); const state = Object.assign( { request, cache: getCache() }, options, options.installationId ? { installationId: Number(options.installationId) } : {}, { log, oauthApp: createOAuthAppAuth({ clientType: "github-app", clientId: options.clientId || "", clientSecret: options.clientSecret || "", request }) } ); return Object.assign(auth.bind(null, state), { hook: hook.bind(null, state) }); } export { createAppAuth, createOAuthUserAuth };