From cb391557a0e1ff7506a1cee0bc66231d1dc1638e Mon Sep 17 00:00:00 2001 From: Sam Harrison Date: Mon, 30 Mar 2020 13:57:22 -0500 Subject: [PATCH 1/2] feat: console warning added when using an invalid API key --- packages/client/src/classes/client.js | 68 ++++++++------------------- packages/client/src/client.spec.js | 29 ++++++++++-- 2 files changed, 45 insertions(+), 52 deletions(-) diff --git a/packages/client/src/classes/client.js b/packages/client/src/classes/client.js index f1f635d0a..649606721 100644 --- a/packages/client/src/classes/client.js +++ b/packages/client/src/classes/client.js @@ -1,8 +1,4 @@ 'use strict'; - -/** - * Dependencies - */ const axios = require('axios'); const pkg = require('../../package.json'); const { @@ -15,26 +11,18 @@ const { }, } = require('@sendgrid/helpers'); -/** - * Twilio SendGrid REST Client - */ +const API_KEY_PREFIX = 'SG.'; + class Client { - /** - * Constructor - */ constructor() { - - //API key this.apiKey = ''; - //Default headers this.defaultHeaders = { - 'Accept': 'application/json', + Accept: 'application/json', 'Content-Type': 'application/json', 'User-agent': 'sendgrid/' + pkg.version + ';nodejs', }; - //Empty default request this.defaultRequest = { baseUrl: 'https://api.sendgrid.com/', url: '', @@ -43,51 +31,45 @@ class Client { }; } - /** - * Set API key - */ setApiKey(apiKey) { this.apiKey = apiKey; + + if (!this.isValidApiKey(apiKey)) { + console.warn(`API key does not start with ${API_KEY_PREFIX}`); + } + } + + isValidApiKey(apiKey) { + return this.isString(apiKey) && apiKey.trim().startsWith(API_KEY_PREFIX); + } + + isString(value) { + return typeof value === 'string' || value instanceof String; } - /** - * Set default header - */ setDefaultHeader(key, value) { this.defaultHeaders[key] = value; return this; } - /** - * Set default request - */ setDefaultRequest(key, value) { this.defaultRequest[key] = value; return this; } - /** - * Create headers for request - */ createHeaders(data) { - - //Merge data with default headers + // Merge data with default headers. const headers = mergeData(this.defaultHeaders, data); - //Add API key, but don't overwrite if header already set + // Add API key, but don't overwrite if header already set. if (typeof headers.Authorization === 'undefined' && this.apiKey) { headers.Authorization = 'Bearer ' + this.apiKey; } - //Return return headers; } - /** - * Create request - */ createRequest(data) { - let options = { url: data.uri || data.url, baseUrl: data.baseUrl, @@ -97,7 +79,7 @@ class Client { headers: data.headers, }; - //Merge data with empty request + // Merge data with default request. options = mergeData(this.defaultRequest, options); options.headers = this.createHeaders(options.headers); options.baseURL = options.baseUrl; @@ -106,52 +88,40 @@ class Client { return options; } - /** - * Do a request - */ request(data, cb) { - - //Create request data = this.createRequest(data); - //Perform request const promise = new Promise((resolve, reject) => { axios(data) .then(response => { - // Successful response return resolve([ new Response(response.status, response.data, response.headers), response.data, ]); }) .catch(error => { - // Response error if (error.response) { if (error.response.status >= 400) { return reject(new ResponseError(error.response)); } } - // Request error return reject(error); }); }); - // Throw and error incase function not passed + // Throw an error in case a callback function was not passed/ if (cb && typeof cb !== 'function') { throw new Error('Callback passed is not a function.'); } - //Execute callback if provided if (cb) { return promise .then(result => cb(null, result)) .catch(error => cb(error, null)); } - //Return promise return promise; } } -//Export class module.exports = Client; diff --git a/packages/client/src/client.spec.js b/packages/client/src/client.spec.js index 65122efe1..d7500303e 100644 --- a/packages/client/src/client.spec.js +++ b/packages/client/src/client.spec.js @@ -13,9 +13,32 @@ const testRequest = (request, statusCode) => { }); }; -/** - * Tests - */ +describe('client', () => { + const sgClient = require('./client'); + + describe('setApiKey', () => { + let consoleWarnSpy; + + beforeEach(() => { + consoleWarnSpy = sinon.spy(console, 'warn'); + }); + + afterEach(() => { + console.warn.restore(); + }); + + it('should not log a warning for a proper API key value', () => { + sgClient.setApiKey('SG.1234567890'); + expect(consoleWarnSpy.notCalled).to.equal(true); + }); + + it('should log a warning for an undefined API key value', () => { + sgClient.setApiKey(undefined); + expect(consoleWarnSpy.calledOnce).to.equal(true); + }); + }); +}); + describe('test_access_settings_activity_get', () => { const request = {}; request.qs = { From aeb5ed0b50b9c1f481eeb24acfc0d4d12858b136 Mon Sep 17 00:00:00 2001 From: Sam Harrison Date: Mon, 30 Mar 2020 15:47:42 -0500 Subject: [PATCH 2/2] fix punctuation --- packages/client/src/classes/client.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/client/src/classes/client.js b/packages/client/src/classes/client.js index 649606721..4d55dade4 100644 --- a/packages/client/src/classes/client.js +++ b/packages/client/src/classes/client.js @@ -35,7 +35,7 @@ class Client { this.apiKey = apiKey; if (!this.isValidApiKey(apiKey)) { - console.warn(`API key does not start with ${API_KEY_PREFIX}`); + console.warn(`API key does not start with "${API_KEY_PREFIX}".`); } } @@ -109,7 +109,7 @@ class Client { }); }); - // Throw an error in case a callback function was not passed/ + // Throw an error in case a callback function was not passed. if (cb && typeof cb !== 'function') { throw new Error('Callback passed is not a function.'); }