UNPKG

@netcentric/cm-notify-core

Version:

Adobe Cloud Manager Pipeline Notifications to Slack, Teams and Email

158 lines (144 loc) 4.34 kB
const { URL } = require('node:url'); const { AuthorizationCode } = require('simple-oauth2'); const { CMUtils } = require('./utils'); /** * @typedef {Object} CredentialsConfig * @property {Object} credentials - The credentials for the OAuth2 client. * @property {Object} token - The token for the OAuth2 client. * */ /** * @typedef {Object} OAuth2ClientType * @property {function} getAccessToken - Retrieves the access token. * @property {function} getAuthUrl - Retrieves the authorization URL. * @property {function} saveTokenFromCode - Saves the token from the authorization code. * */ /** * Class representing an OAuth2Client. */ class OAuth2Client { /** * @constructor * @param fromEmail {string} - The email address of the sender. * @param dataPath {string} - The path to the directory containing credentials JSON file. * @throws {Error} - If fromEmail is not provided. * @returns {OAuth2ClientType} - The OAuth2Client instance. */ constructor(fromEmail, dataPath) { this.fromEmail = fromEmail; this.dataPath = dataPath; if (!this.fromEmail) { throw new Error('Missing fromEmail param'); } this.CONFIG = { TOKEN_FILENAME: 'google-token.json', CREDENTIALS_FILENAME: 'google-credentials.json', } const credentials = CMUtils.getJsonData(this.CONFIG.CREDENTIALS_FILENAME, dataPath); this.client = this.__getAuthClient(credentials); this.redirectUri = credentials.installed.redirect_uris[0]; return this.__public(); } /** * Creates a public interface for the OAuth2Client. * @returns {OAuth2ClientType} * @private */ __public() { return { getAccessToken: this.getAccessToken.bind(this), getAuthUrl: this.getAuthUrl.bind(this), saveTokenFromCode: this.saveTokenFromCode.bind(this) } } get token() { return CMUtils.getJsonData(this.CONFIG.TOKEN_FILENAME, this.dataPath); } /** * Retrieves the access token from the token file. * @returns {Promise<*>} */ getAccessToken() { if (!this.token) { throw new Error('Missing token file'); } const accessToken = this.client.createToken(this.token); return this.__ensureFreshToken(accessToken); } /** * Generates the authorization URL for the OAuth2 client. * @param state * @returns {String} */ getAuthUrl(state = 'secure_random_state') { const authUrl = this.client.authorizeURL({ redirect_uri: this.redirectUri, scope: 'https://www.googleapis.com/auth/gmail.send', state, access_type: 'offline', login_hint: this.fromEmail, }); console.log('Open this URL in a browser:', authUrl); return authUrl; } /** * Saves the token from the authorization code. * @param code * @returns {Promise<AccessToken>} */ async saveTokenFromCode(code) { const tokenParams = { code, redirect_uri: this.redirectUri, scope: 'https://www.googleapis.com/auth/gmail.send', }; const rawToken = await this.client.getToken(tokenParams); CMUtils.saveJsonData(this.CONFIG.TOKEN_FILENAME, rawToken.token, this.dataPath); return this.client.createToken(rawToken.token); } /** * Creates an OAuth2 client and sets the credentials and token. * @param credentials * @returns AuthorizationCode * @private */ __getAuthClient(credentials) { if (!credentials) { throw new Error('Missing credentials'); } const { client_secret, client_id, token_uri, auth_uri } = credentials.installed; const tokenUrl = new URL(token_uri); const authUrl = new URL(auth_uri); const config = { client: { id: client_id, secret: client_secret, }, auth: { tokenHost: `${tokenUrl.origin}`, tokenPath: `${tokenUrl.pathname}`, authorizeHost: `${authUrl.origin}`, authorizePath: `${authUrl.pathname}` }, }; const client = new AuthorizationCode(config); return client; } /** * Ensures that the token is fresh and not expired. * @param tokenObj * @returns {Promise<*>} * @private */ async __ensureFreshToken(tokenObj) { if (tokenObj.expired()) { console.log('Token expired, refreshing...'); return tokenObj.refresh(); } return tokenObj; } } module.exports = { OAuth2Client }