Skip to content

Commit

Permalink
fix: don't send header values that are 'undefined' (#360)
Browse files Browse the repository at this point in the history
  • Loading branch information
kanadgupta authored Aug 26, 2021
1 parent a5e601c commit ae03c1e
Show file tree
Hide file tree
Showing 10 changed files with 82 additions and 53 deletions.
26 changes: 26 additions & 0 deletions __tests__/lib/cleanHeaders.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
const { cleanHeaders } = require('../../src/lib/cleanHeaders');

describe('cleanHeaders', () => {
it('should b64-encode key in ReadMe-friendly format', () => {
expect(cleanHeaders('test')).toStrictEqual({ Authorization: 'Basic dGVzdDo=' });
});

it('should filter out undefined headers', () => {
expect(cleanHeaders('test', { 'x-readme-version': undefined })).toStrictEqual({ Authorization: 'Basic dGVzdDo=' });
});

it('should filter out null headers', () => {
expect(cleanHeaders('test', { 'x-readme-version': undefined, Accept: null })).toStrictEqual({
Authorization: 'Basic dGVzdDo=',
});
});

it('should pass in properly defined headers', () => {
expect(
cleanHeaders('test', { 'x-readme-version': undefined, Accept: null, 'Content-Type': 'application/json' })
).toStrictEqual({
Authorization: 'Basic dGVzdDo=',
'Content-Type': 'application/json',
});
});
});
12 changes: 5 additions & 7 deletions src/cmds/docs/edit.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ const fs = require('fs');
const editor = require('editor');
const { promisify } = require('util');
const APIError = require('../../lib/apiError');
const { cleanHeaders } = require('../../lib/cleanHeaders');
const { getProjectVersion } = require('../../lib/versionSelect');
const { handleRes } = require('../../lib/handleRes');
const fetch = require('node-fetch');
Expand Down Expand Up @@ -52,15 +53,13 @@ exports.run = async function (opts) {
});

const filename = `${slug}.md`;
const encodedString = Buffer.from(`${key}:`).toString('base64');

const existingDoc = await fetch(`${config.host}/api/v1/docs/${slug}`, {
method: 'get',
headers: {
headers: cleanHeaders(key, {
'x-readme-version': selectedVersion,
Authorization: `Basic ${encodedString}`,
Accept: 'application/json',
},
}),
}).then(res => handleRes(res));

await writeFile(filename, existingDoc.body);
Expand All @@ -72,11 +71,10 @@ exports.run = async function (opts) {

return fetch(`${config.host}/api/v1/docs/${slug}`, {
method: 'put',
headers: {
headers: cleanHeaders(key, {
'x-readme-version': selectedVersion,
Authorization: `Basic ${encodedString}`,
'Content-Type': 'application/json',
},
}),
body: JSON.stringify(
Object.assign(existingDoc, {
body: updatedDoc,
Expand Down
18 changes: 7 additions & 11 deletions src/cmds/docs/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ const config = require('config');
const crypto = require('crypto');
const frontMatter = require('gray-matter');
const { promisify } = require('util');
const { cleanHeaders } = require('../../lib/cleanHeaders');
const { getProjectVersion } = require('../../lib/versionSelect');
const { handleRes } = require('../../lib/handleRes');
const fetch = require('node-fetch');
Expand Down Expand Up @@ -70,18 +71,15 @@ exports.run = async function (opts) {
return Promise.reject(new Error(`We were unable to locate Markdown files in ${folder}.`));
}

const encodedString = Buffer.from(`${key}:`).toString('base64');

function createDoc(slug, file, hash, err) {
if (err.error !== 'DOC_NOTFOUND') return Promise.reject(err);

return fetch(`${config.host}/api/v1/docs`, {
method: 'post',
headers: {
headers: cleanHeaders(key, {
'x-readme-version': selectedVersion,
Authorization: `Basic ${encodedString}`,
'Content-Type': 'application/json',
},
}),
body: JSON.stringify({
slug,
body: file.content,
Expand All @@ -98,11 +96,10 @@ exports.run = async function (opts) {

return fetch(`${config.host}/api/v1/docs/${slug}`, {
method: 'put',
headers: {
headers: cleanHeaders(key, {
'x-readme-version': selectedVersion,
Authorization: `Basic ${encodedString}`,
'Content-Type': 'application/json',
},
}),
body: JSON.stringify(
Object.assign(existingDoc, {
body: file.content,
Expand All @@ -124,11 +121,10 @@ exports.run = async function (opts) {

return fetch(`${config.host}/api/v1/docs/${slug}`, {
method: 'get',
headers: {
headers: cleanHeaders(key, {
'x-readme-version': selectedVersion,
Authorization: `Basic ${encodedString}`,
Accept: 'application/json',
},
}),
})
.then(res => res.json())
.then(res => {
Expand Down
13 changes: 5 additions & 8 deletions src/cmds/openapi.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ const { prompt } = require('enquirer');
const OASNormalize = require('oas-normalize');
const promptOpts = require('../lib/prompts');
const APIError = require('../lib/apiError');
const { cleanHeaders } = require('../lib/cleanHeaders');
const { getProjectVersion } = require('../lib/versionSelect');
const fetch = require('node-fetch');
const FormData = require('form-data');
Expand Down Expand Up @@ -61,8 +62,6 @@ exports.run = async function (opts) {
return Promise.reject(new Error('No project API key provided. Please use `--key`.'));
}

const encodedString = Buffer.from(`${key}:`).toString('base64');

async function callApi(specPath, versionCleaned) {
// @todo Tailor messaging to what is actually being handled here. If the user is uploading a Swagger file, never mention that they uploaded/updated an OpenAPI file.

Expand Down Expand Up @@ -122,12 +121,11 @@ exports.run = async function (opts) {
formData.append('spec', bundledSpec);

const options = {
headers: {
headers: cleanHeaders(key, {
'x-readme-version': versionCleaned,
'x-readme-source': 'cli',
Authorization: `Basic ${encodedString}`,
Accept: 'application/json',
},
}),
body: formData,
};

Expand Down Expand Up @@ -163,10 +161,9 @@ exports.run = async function (opts) {
function getSpecs(url) {
return fetch(`${config.host}${url}`, {
method: 'get',
headers: {
headers: cleanHeaders(key, {
'x-readme-version': versionCleaned,
Authorization: `Basic ${encodedString}`,
},
}),
});
}

Expand Down
11 changes: 4 additions & 7 deletions src/cmds/versions/create.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ const semver = require('semver');
const { prompt } = require('enquirer');
const promptOpts = require('../../lib/prompts');
const APIError = require('../../lib/apiError');
const { cleanHeaders } = require('../../lib/cleanHeaders');
const { handleRes } = require('../../lib/handleRes');
const fetch = require('node-fetch');

Expand Down Expand Up @@ -54,7 +55,6 @@ exports.args = [
exports.run = async function (opts) {
let versionList;
const { key, version, codename, fork, main, beta, isPublic } = opts;
const encodedString = Buffer.from(`${key}:`).toString('base64');

if (!key) {
return Promise.reject(new Error('No project API key provided. Please use `--key`.'));
Expand All @@ -69,9 +69,7 @@ exports.run = async function (opts) {
if (!fork) {
versionList = await fetch(`${config.host}/api/v1/version`, {
method: 'get',
headers: {
Authorization: `Basic ${encodedString}`,
},
headers: cleanHeaders(key),
}).then(res => handleRes(res));
}

Expand All @@ -84,11 +82,10 @@ exports.run = async function (opts) {

return fetch(`${config.host}/api/v1/version`, {
method: 'post',
headers: {
headers: cleanHeaders(key, {
Accept: 'application/json',
'Content-Type': 'application/json',
Authorization: `Basic ${encodedString}`,
},
}),
body: JSON.stringify({
version,
codename: codename || '',
Expand Down
6 changes: 2 additions & 4 deletions src/cmds/versions/delete.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
const config = require('config');
const APIError = require('../../lib/apiError');
const { getProjectVersion } = require('../../lib/versionSelect');
const { cleanHeaders } = require('../../lib/cleanHeaders');
const fetch = require('node-fetch');

exports.command = 'versions:delete';
Expand All @@ -25,7 +26,6 @@ exports.args = [

exports.run = async function (opts) {
const { key, version } = opts;
const encodedString = Buffer.from(`${key}:`).toString('base64');

if (!key) {
return Promise.reject(new Error('No project API key provided. Please use `--key`.'));
Expand All @@ -37,9 +37,7 @@ exports.run = async function (opts) {

return fetch(`${config.host}/api/v1/version/${selectedVersion}`, {
method: 'delete',
headers: {
Authorization: `Basic ${encodedString}`,
},
headers: cleanHeaders(key),
}).then(res => {
if (res.error) {
return Promise.reject(new APIError(res));
Expand Down
6 changes: 2 additions & 4 deletions src/cmds/versions/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ const Table = require('cli-table');
const config = require('config');
const versionsCreate = require('./create');
const APIError = require('../../lib/apiError');
const { cleanHeaders } = require('../../lib/cleanHeaders');
const fetch = require('node-fetch');

exports.command = 'versions';
Expand Down Expand Up @@ -82,7 +83,6 @@ const getVersionFormatted = version => {

exports.run = function (opts) {
const { key, version, raw } = opts;
const encodedString = Buffer.from(`${key}:`).toString('base64');

if (!key) {
return Promise.reject(new Error('No project API key provided. Please use `--key`.'));
Expand All @@ -92,9 +92,7 @@ exports.run = function (opts) {

return fetch(uri, {
method: 'get',
headers: {
Authorization: `Basic ${encodedString}`,
},
headers: cleanHeaders(key),
})
.then(res => res.json())
.then(data => {
Expand Down
11 changes: 4 additions & 7 deletions src/cmds/versions/update.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ const config = require('config');
const { prompt } = require('enquirer');
const promptOpts = require('../../lib/prompts');
const APIError = require('../../lib/apiError');
const { cleanHeaders } = require('../../lib/cleanHeaders');
const { getProjectVersion } = require('../../lib/versionSelect');
const fetch = require('node-fetch');
const { handleRes } = require('../../lib/handleRes');
Expand Down Expand Up @@ -47,7 +48,6 @@ exports.args = [

exports.run = async function (opts) {
const { key, version, codename, newVersion, main, beta, isPublic, deprecated } = opts;
const encodedString = Buffer.from(`${key}:`).toString('base64');

if (!key) {
return Promise.reject(new Error('No project API key provided. Please use `--key`.'));
Expand All @@ -59,20 +59,17 @@ exports.run = async function (opts) {

const foundVersion = await fetch(`${config.host}/api/v1/version/${selectedVersion}`, {
method: 'get',
headers: {
Authorization: `Basic ${encodedString}`,
},
headers: cleanHeaders(key),
}).then(res => handleRes(res));

const promptResponse = await prompt(promptOpts.createVersionPrompt([{}], opts, foundVersion));

return fetch(`${config.host}/api/v1/version/${selectedVersion}`, {
method: 'put',
headers: {
headers: cleanHeaders(key, {
Accept: 'application/json',
'Content-Type': 'application/json',
Authorization: `Basic ${encodedString}`,
},
}),
body: JSON.stringify({
codename: codename || '',
version: newVersion || promptResponse.newVersion,
Expand Down
23 changes: 23 additions & 0 deletions src/lib/cleanHeaders.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/**
* Returns the basic auth header and any other defined headers for use in node-fetch API calls.
* @param {string} key The ReadMe project API key
* @param {Object} inputHeaders Any additional headers to be cleaned
* @returns An object with cleaned request headers for usage in the node-fetch requests to the ReadMe API.
*/
function cleanHeaders(key, inputHeaders = {}) {
const encodedKey = Buffer.from(`${key}:`).toString('base64');
const headers = {
Authorization: `Basic ${encodedKey}`,
};

Object.keys(inputHeaders).forEach(header => {
// For some reason, node-fetch will send in the string 'undefined'
// if you pass in an undefined value for a header,
// so that's why headers are added incrementally.
if (typeof inputHeaders[header] === 'string') headers[header] = inputHeaders[header];
});

return headers;
}

module.exports = { cleanHeaders };
9 changes: 4 additions & 5 deletions src/lib/versionSelect.js
Original file line number Diff line number Diff line change
@@ -1,25 +1,24 @@
const { prompt } = require('enquirer');
const promptOpts = require('./prompts');
const { cleanHeaders } = require('./cleanHeaders');
const fetch = require('node-fetch');
const config = require('config');
const APIError = require('./apiError');

async function getProjectVersion(versionFlag, key, allowNewVersion) {
const encodedString = Buffer.from(`${key}:`).toString('base64');

try {
if (versionFlag) {
return await fetch(`${config.host}/api/v1/version/${versionFlag}`, {
method: 'get',
headers: { Authorization: `Basic ${encodedString}` },
headers: cleanHeaders(key),
})
.then(res => res.json())
.then(res => res.version);
}

const versionList = await fetch(`${config.host}/api/v1/version`, {
method: 'get',
headers: { Authorization: `Basic ${encodedString}` },
headers: cleanHeaders(key),
}).then(res => res.json());

if (allowNewVersion) {
Expand All @@ -29,7 +28,7 @@ async function getProjectVersion(versionFlag, key, allowNewVersion) {

await fetch(`${config.host}/api/v1/version`, {
method: 'post',
headers: { Authorization: `Basic ${encodedString}`, 'Content-Type': 'application/json' },
headers: cleanHeaders(key, { 'Content-Type': 'application/json' }),
body: JSON.stringify({
from: versionList[0].version,
version: newVersion,
Expand Down

0 comments on commit ae03c1e

Please sign in to comment.