diff --git a/src/Checkout.js b/src/Checkout.js index 77c198f..55e56c9 100644 --- a/src/Checkout.js +++ b/src/Checkout.js @@ -1,6 +1,27 @@ import * as CONFIG from './config'; import * as ENDPOINTS from './index'; +/** + * Determine the full URL based on the environment and subdomain. + * + * @param {string} environment + * @param {object} options + * @returns {string} + */ +const determineUrl = (environment, options) => { + const apiUrl = new URL(environment); + + if (options && options.subdomain) { + const subdomain = options.subdomain; + if (typeof subdomain === 'string' && /^[0-9a-z]{8,11}$/.test(subdomain)) { + const { protocol, port, hostname } = apiUrl; + return new URL(`${protocol}//${subdomain}.${hostname}${port ? `:${port}` : ''}`).toString().slice(0, -1); + } + } + + return apiUrl.toString().slice(0, -1); +}; + const determineHost = (key, options) => { // If specified, use the custom host if (options && options.host) { @@ -17,9 +38,9 @@ const determineHost = (key, options) => { (process.env.CKO_ENVIRONMENT && process.env.CKO_ENVIRONMENT.toLowerCase().trim() === 'live') ) { - return CONFIG.LIVE_BASE_URL; + return determineUrl(CONFIG.LIVE_BASE_URL, options); } - return CONFIG.SANDBOX_BASE_URL; + return determineUrl(CONFIG.SANDBOX_BASE_URL, options); } // Priority 2: oAuth declared vars if (options && options.client) { @@ -28,9 +49,9 @@ const determineHost = (key, options) => { (options.environment && options.environment.toLowerCase().trim() === 'production') || (options.environment && options.environment.toLowerCase().trim() === 'live') ) { - return CONFIG.LIVE_BASE_URL; + return determineUrl(CONFIG.LIVE_BASE_URL, options); } - return CONFIG.SANDBOX_BASE_URL; + return determineUrl(CONFIG.SANDBOX_BASE_URL, options); } // Priority 3: MBC or NAS static keys @@ -39,8 +60,8 @@ const determineHost = (key, options) => { key = key.replace('Bearer', '').trim(); } return CONFIG.MBC_LIVE_SECRET_KEY_REGEX.test(key) || CONFIG.NAS_LIVE_SECRET_KEY_REGEX.test(key) - ? CONFIG.LIVE_BASE_URL - : CONFIG.SANDBOX_BASE_URL; + ? determineUrl(CONFIG.LIVE_BASE_URL, options) + : determineUrl(CONFIG.SANDBOX_BASE_URL, options); }; const determineSecretKey = (key) => { @@ -133,6 +154,7 @@ export default class Checkout { headers: options && options.headers ? options.headers : {}, access: undefined, httpClient: options && options.httpClient ? options.httpClient : undefined, + subdomain: options && options.subdomain ? options.subdomain : undefined, }; this.payments = new ENDPOINTS.Payments(this.config); diff --git a/test/config/config.js b/test/config/config.js index 5fd2c9b..6e7f86f 100644 --- a/test/config/config.js +++ b/test/config/config.js @@ -139,7 +139,52 @@ describe('NAS oAuth', () => { expect(cko.config.agent).to.be.undefined; }); - it('should default to sandbox and gateway scope with oAuth credentials', () => { + it('should initialize with oAuth credentials with subdomain', () => { + const cko = new Checkout('2p7YQ37fHiRr8O6lQAikl8enICesB1dvAJrpmE2nZfEOpxzE-', { + client: 'ack_vvzhoai466su3j3vbxb47ts5oe', + scope: ['gateway'], + environment: 'sandbox', + subdomain: '12345domain' + }); + expect(cko).to.be.instanceOf(Checkout); + expect(cko.config.client).to.equal('ack_vvzhoai466su3j3vbxb47ts5oe'); + expect(cko.config.host).to.equal('https://12345domain.api.sandbox.checkout.com'); + expect(cko.config.scope[0]).to.equal('gateway'); + expect(cko.config.secret).to.equal('2p7YQ37fHiRr8O6lQAikl8enICesB1dvAJrpmE2nZfEOpxzE-'); + expect(cko.config.agent).to.be.undefined; + }); + + it('should initialize with oAuth credentials with bad subdomain', () => { + const cko = new Checkout('2p7YQ37fHiRr8O6lQAikl8enICesB1dvAJrpmE2nZfEOpxzE-', { + client: 'ack_vvzhoai466su3j3vbxb47ts5oe', + scope: ['gateway'], + environment: 'sandbox', + subdomain: '12345domain12345' + }); + expect(cko).to.be.instanceOf(Checkout); + expect(cko.config.client).to.equal('ack_vvzhoai466su3j3vbxb47ts5oe'); + expect(cko.config.host).to.equal('https://api.sandbox.checkout.com'); + expect(cko.config.scope[0]).to.equal('gateway'); + expect(cko.config.secret).to.equal('2p7YQ37fHiRr8O6lQAikl8enICesB1dvAJrpmE2nZfEOpxzE-'); + expect(cko.config.agent).to.be.undefined; + }); + + it('should initialize with oAuth credentials with subdomain empty', () => { + const cko = new Checkout('2p7YQ37fHiRr8O6lQAikl8enICesB1dvAJrpmE2nZfEOpxzE-', { + client: 'ack_vvzhoai466su3j3vbxb47ts5oe', + scope: ['gateway'], + environment: 'sandbox', + subdomain: '' + }); + expect(cko).to.be.instanceOf(Checkout); + expect(cko.config.client).to.equal('ack_vvzhoai466su3j3vbxb47ts5oe'); + expect(cko.config.host).to.equal('https://api.sandbox.checkout.com'); + expect(cko.config.scope[0]).to.equal('gateway'); + expect(cko.config.secret).to.equal('2p7YQ37fHiRr8O6lQAikl8enICesB1dvAJrpmE2nZfEOpxzE-'); + expect(cko.config.agent).to.be.undefined; + }); + + it('should default to sandbox and gateway scope with oAuth credentials', () => { const cko = new Checkout('2p7YQ37fHiRr8O6lQAikl8enICesB1dvAJrpmE2nZfEOpxzE-', { client: 'ack_vvzhoai466su3j3vbxb47ts5oe', }); @@ -148,7 +193,7 @@ describe('NAS oAuth', () => { expect(cko.config.scope).to.equal('gateway'); }); - it('should default to sandbox and gateway scope with oAuth credentials from env vars', () => { + it('should default to sandbox and gateway scope with oAuth credentials from env vars', () => { process.env.CKO_SECRET = '2p7YQ37fHiRr8O6lQAikl8enICesB1dvAJrpmE2nZfEOpxzE-'; process.env.CKO_CLIENT = 'ack_vvzhoai466su3j3vbxb47ts5oe';