diff --git a/app/network/network.js b/app/network/network.js index f11f78730..62e208d60 100644 --- a/app/network/network.js +++ b/app/network/network.js @@ -17,7 +17,7 @@ import * as querystring from '../common/querystring'; import * as util from '../common/misc.js'; import {AUTH_AWS_IAM, AUTH_BASIC, AUTH_DIGEST, AUTH_NETRC, AUTH_NTLM, CONTENT_TYPE_FORM_DATA, CONTENT_TYPE_FORM_URLENCODED, getAppVersion, STATUS_CODE_PLUGIN_ERROR} from '../common/constants'; import {describeByteSize, hasAuthHeader, hasContentTypeHeader, hasUserAgentHeader, setDefaultProtocol} from '../common/misc'; -import {getRenderedRequest} from '../common/render'; +import {getRenderedRequest, getRenderContext} from '../common/render'; import fs from 'fs'; import * as db from '../common/database'; import * as CACerts from './cacert'; @@ -634,10 +634,11 @@ export async function send (requestId: string, environmentId: string) { } const renderedRequestBeforePlugins = await getRenderedRequest(request, environmentId); + const renderedContextBeforePlugins = await getRenderContext(request, environmentId, ancestors); let renderedRequest: RenderedRequest; try { - renderedRequest = await _applyRequestPluginHooks(renderedRequestBeforePlugins); + renderedRequest = await _applyRequestPluginHooks(renderedRequestBeforePlugins, renderedContextBeforePlugins); } catch (err) { return { response: { @@ -661,14 +662,14 @@ export async function send (requestId: string, environmentId: string) { return _actuallySend(renderedRequest, workspace, settings); } -async function _applyRequestPluginHooks (renderedRequest: RenderedRequest): Promise { +async function _applyRequestPluginHooks (renderedRequest: RenderedRequest, renderedContext: Object): Promise { let newRenderedRequest = renderedRequest; for (const {plugin, hook} of await plugins.getRequestHooks()) { newRenderedRequest = clone(newRenderedRequest); const context = { ...pluginContexts.app.init(plugin), - ...pluginContexts.request.init(plugin, newRenderedRequest) + ...pluginContexts.request.init(plugin, newRenderedRequest, renderedContext) }; try { diff --git a/app/plugins/context/__tests__/request.test.js b/app/plugins/context/__tests__/request.test.js index f334af4fb..e292fa3e5 100644 --- a/app/plugins/context/__tests__/request.test.js +++ b/app/plugins/context/__tests__/request.test.js @@ -9,6 +9,14 @@ const PLUGIN = { module: {} }; +const CONTEXT = { + user_key: 'my_user_key', + hello: 'world', + array_test: ['a', 'b'], + object_test: {a: 'A', b: 'B'}, + null_test: null +}; + describe('init()', () => { beforeEach(async () => { await globalBeforeEach(); @@ -17,7 +25,7 @@ describe('init()', () => { }); it('initializes correctly', async () => { - const result = plugin.init(PLUGIN, await models.request.getById('req_1')); + const result = plugin.init(PLUGIN, await models.request.getById('req_1'), CONTEXT); expect(Object.keys(result)).toEqual(['request']); expect(Object.keys(result.request)).toEqual([ 'getId', @@ -25,11 +33,14 @@ describe('init()', () => { 'getUrl', 'getMethod', 'getHeader', + 'getHeaders', 'hasHeader', 'removeHeader', 'setHeader', 'addHeader', - 'setCookie' + 'setCookie', + 'getEnvironmentVariable', + 'getEnvironment' ]); }); @@ -55,7 +66,7 @@ describe('request.*', () => { }); it('works for basic getters', async () => { - const result = plugin.init(PLUGIN, await models.request.getById('req_1')); + const result = plugin.init(PLUGIN, await models.request.getById('req_1'), CONTEXT); expect(result.request.getId()).toBe('req_1'); expect(result.request.getName()).toBe('My Request'); expect(result.request.getUrl()).toBe(''); @@ -63,7 +74,13 @@ describe('request.*', () => { }); it('works for headers', async () => { - const result = plugin.init(PLUGIN, await models.request.getById('req_1')); + const result = plugin.init(PLUGIN, await models.request.getById('req_1'), CONTEXT); + + // getHeaders() + expect(result.request.getHeaders()).toEqual([ + {name: 'hello', value: 'world'}, + {name: 'Content-Type', value: 'application/json'} + ]); // getHeader() expect(result.request.getHeader('content-type')).toBe('application/json'); @@ -91,10 +108,33 @@ describe('request.*', () => { const request = await models.request.getById('req_1'); request.cookies = []; // Because the plugin technically needs a RenderedRequest - const result = plugin.init(PLUGIN, request); + const result = plugin.init(PLUGIN, request, CONTEXT); result.request.setCookie('foo', 'bar'); result.request.setCookie('foo', 'baz'); expect(request.cookies).toEqual([{name: 'foo', value: 'baz'}]); }); + + it('works for environment', async () => { + const request = await models.request.getById('req_1'); + request.cookies = []; // Because the plugin technically needs a RenderedRequest + + const result = plugin.init(PLUGIN, request, CONTEXT); + + // getEnvironment + expect(result.request.getEnvironment()).toEqual({ + user_key: 'my_user_key', + hello: 'world', + array_test: ['a', 'b'], + object_test: {a: 'A', b: 'B'}, + null_test: null + }); + + // getEnvironmentVariable + expect(result.request.getEnvironmentVariable('user_key')).toBe('my_user_key'); + expect(result.request.getEnvironmentVariable('hello')).toBe('world'); + expect(result.request.getEnvironmentVariable('array_test')).toEqual(['a', 'b']); + expect(result.request.getEnvironmentVariable('object_test')).toEqual({a: 'A', b: 'B'}); + expect(result.request.getEnvironmentVariable('null_test')).toBe(null); + }); }); diff --git a/app/plugins/context/request.js b/app/plugins/context/request.js index c6b4cec47..dedf4b9e7 100644 --- a/app/plugins/context/request.js +++ b/app/plugins/context/request.js @@ -3,7 +3,11 @@ import type {Plugin} from '../'; import type {RenderedRequest} from '../../common/render'; import * as misc from '../../common/misc'; -export function init (plugin: Plugin, renderedRequest: RenderedRequest): {request: Object} { +export function init ( + plugin: Plugin, + renderedRequest: RenderedRequest, + renderedContext: Object +): {request: Object} { if (!renderedRequest) { throw new Error('contexts.request initialized without request'); } @@ -33,6 +37,9 @@ export function init (plugin: Plugin, renderedRequest: RenderedRequest): {reques return null; } }, + getHeaders (): Array<{name: string, value: string}> { + return renderedRequest.headers.map(h => ({ name: h.name, value: h.value })); + }, hasHeader (name: string): boolean { return this.getHeader(name) !== null; }, @@ -63,6 +70,12 @@ export function init (plugin: Plugin, renderedRequest: RenderedRequest): {reques } else { renderedRequest.cookies.push({name, value}); } + }, + getEnvironmentVariable (name: string): string | number | boolean | Object | Array | null { + return renderedContext[name]; + }, + getEnvironment (): string | number | boolean | Object | Array | null { + return renderedContext; } // NOTE: For these to make sense, we'd need to account for cookies in the jar as well diff --git a/app/plugins/install.js b/app/plugins/install.js index f4d6b52b0..6c1a6647f 100644 --- a/app/plugins/install.js +++ b/app/plugins/install.js @@ -71,21 +71,13 @@ export default async function (moduleName: string): Promise { async function _isInsomniaPlugin (moduleName: string): Promise { return new Promise((resolve, reject) => { childProcess.exec( - `npm show ${moduleName} insomnia version name dist.shasum dist.tarball`, - (err, stdout, stderr) => { + `npm show ${moduleName} --json`, (err, stdout, stderr) => { if (err && stderr.includes('E404')) { reject(new Error(`${moduleName} not found on npm`)); return; } - const lines = stdout.split('\n').filter(l => !!l); - const info = {}; - for (const line of lines) { - const match = line.match(/(.*) = '(.*)'/); - - // Strip quotes off of the value - info[match[1]] = match[2]; - } + const info = JSON.parse(stdout); if (!info.hasOwnProperty('insomnia')) { reject(new Error(`"${moduleName}" not a plugin! Package missing "insomnia" attribute`)); @@ -97,8 +89,8 @@ async function _isInsomniaPlugin (moduleName: string): Promise { name: info.name, version: info.version, dist: { - shasum: info['dist.shasum'], - tarball: info['dist.tarball'] + shasum: info.dist.shasum, + tarball: info.dist.tarball } }); }