import { AsymmetricAlgorithm , encodeAsymmetric } from "atlassian-jwt" ; import AuthToken , { ONE_MINUTE , TEN_MINUTES } from "./auth-token" ; import * as PrivateKey from "probot/lib/private-key" ; import LRUCache from "lru-cache" ; import { InstallationId } from "./installation-id" ; export type KeyLocator = ( installationId : InstallationId ) => string ; /**
 * By default, we just look for a key in the `PRIVATE_KEY` env var.
 */ export const cloudKeyLocator = ( ) => { return PrivateKey . findPrivateKey ( ) || "" ; } ; see https see https export default class AppTokenHolder { private readonly privateKeyLocator : KeyLocator ; private readonly appTokenCache : LRUCache < string , AuthToken > ; private static instance : AppTokenHolder ; constructor ( keyLocator ? ) { this . appTokenCache = new LRUCache < string , AuthToken > ( { max : 1000 } ) ; this . privateKeyLocator = keyLocator || cloudKeyLocator ; } public static getInstance ( ) { if ( ! AppTokenHolder . instance ) { AppTokenHolder . instance = new AppTokenHolder ( ) ; } return AppTokenHolder . instance ; } /**
     * Gets the current app token or creates a new one if the old is about to expire.
     */ public getAppToken ( appId ) { let currentToken = this . appTokenCache . get ( appId . toString ( ) ) ; if ( ! currentToken || currentToken . isAboutToExpire ( ) ) { const key = this . privateKeyLocator ( appId ) ; currentToken = AppTokenHolder . createAppJwt ( key , appId . appId ) ; this . appTokenCache . set ( appId . toString ( ) , currentToken ) ; } return currentToken ; } /**
     * Generates a JWT using the private key of the GitHub app to authorize against the GitHub API.
     */ private static createAppJwt ( key , appId ) { const expirationDate = new Date ( Date . now ( ) + TEN_MINUTES ) ; const jwtPayload = { iat : Math . floor ( ( Date . now ( ) - ONE_MINUTE ) / 1000 ) , exp : Math . floor ( expirationDate . getTime ( ) / 1000 ) , iss : appId . toString ( ) } ; return new AuthToken ( encodeAsymmetric ( jwtPayload , key , AsymmetricAlgorithm . RS256 ) , expirationDate ) ; } public clear ( ) { this . appTokenCache . reset ( ) ; } }