akamai-edgegrid 3.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,210 @@
1
+ # EdgeGrid for Node.js
2
+
3
+ [![Build Status](https://travis-ci.org/akamai/AkamaiOPEN-edgegrid-node.svg?branch=master)](https://travis-ci.org/akamai/AkamaiOPEN-edgegrid-node)
4
+
5
+ This library implements an Authentication handler for the Akamai EdgeGrid Authentication scheme in Node.js.
6
+
7
+ It’s Akamai’s current and officially supported version of AkamaiOPEN EdgeGrid for Node.js.
8
+ You can find the most up-to-date package in [NPM](https://www.npmjs.com/package/akamai-edgegrid) under `akamai-edgegrid`.
9
+
10
+ > __IMPORTANT:__ Akamai will not maintain the `edgegrid` package in NPM going forward.
11
+
12
+ ## Installation
13
+
14
+ `npm install --save akamai-edgegrid`
15
+
16
+ ## Example
17
+
18
+ ### Credentials
19
+
20
+ To use Akamai APIs you must first register and authorize a set of credentials through [Control Center](https://control.akamai.com). You can find more information on creating and authorizing credentials at [Authenticate with EdgeGrid](https://developer.akamai.com/getting-started/edgegrid).
21
+
22
+ ### .edgerc authentication
23
+
24
+ The preferred method of using the library involves providing the path to an `.edgerc` file. This file contains the authentication credentials used to sign your requests.
25
+
26
+ > __NOTE__: Requests to the API are signed with a timestamp and are executed immediately.
27
+
28
+ ```javascript
29
+ var EdgeGrid = require('akamai-edgegrid');
30
+
31
+ var data = 'bodyData';
32
+
33
+ // Supply the path to your .edgerc file and name
34
+ // of the section with authorization to the client
35
+ // you are calling (default section is 'default')
36
+ var eg = new EdgeGrid({
37
+ path: '/path/to/.edgerc',
38
+ section: 'section-name'
39
+ });
40
+
41
+ eg.auth({
42
+ path: '/diagnostic-tools/v1/locations',
43
+ method: 'GET',
44
+ headers: {},
45
+ body: data
46
+ });
47
+
48
+ eg.send(function(error, response, body) {
49
+ console.log(body);
50
+ });
51
+ ```
52
+
53
+ An `.edgerc` file contains sections for each of your API client credentials and is usually hosted in your home directory:
54
+
55
+ ```plaintext
56
+ [default]
57
+ host = akaa-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.luna.akamaiapis.net/
58
+ client_token = akab-XXXXXXXXXXXXXXXX-XXXXXXXXXXXXXXXX
59
+ client_secret = XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
60
+ access_token = akab-XXXXXXXXXXXXXXXX-XXXXXXXXXXXXXXXX
61
+ max-body = 131072
62
+
63
+ [section-name]
64
+ host = akaa-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.luna.akamaiapis.net/
65
+ client_token = akab-XXXXXXXXXXXXXXXX-XXXXXXXXXXXXXXXX
66
+ client_secret = XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
67
+ access_token = akab-XXXXXXXXXXXXXXXX-XXXXXXXXXXXXXXXX
68
+ max-body = 131072
69
+ ```
70
+
71
+ ### Manual authentication
72
+
73
+ You can also authenticate manually by hard coding your credential values and passing them to the EdgeGrid client:
74
+
75
+ ```javascript
76
+ var clientToken = "akab-client-token-xxx-xxxxxxxxxxxxxxxx",
77
+ clientSecret = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=",
78
+ accessToken = "akab-access-token-xxx-xxxxxxxxxxxxxxxx",
79
+ baseUri = "https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/";
80
+
81
+ var eg = new EdgeGrid(clientToken, clientSecret, accessToken, baseUri);
82
+ ```
83
+
84
+ ### Chaining
85
+
86
+ You can also chain calls using the `akamai-edgegrid` like in this example:
87
+
88
+ ```javascript
89
+ ...
90
+ eg.auth({
91
+ path: '/papi/v1/groups',
92
+ method: 'GET',
93
+ headers: {},
94
+ }).send(function (error, response, body) {
95
+ console.log(body);
96
+ });
97
+ ```
98
+ ### Headers
99
+
100
+ Headers for the request must be supplied in an object as name-value pairs. You do not need to supply form-data headers or content lengths - that will cause authentication headers on the API.
101
+
102
+ ```javascript
103
+ eg.auth({
104
+ path: '/papi/v1/groups',
105
+ method: 'GET',
106
+ headers: {
107
+ 'Accept': "application/json"
108
+ }
109
+ });
110
+ ```
111
+
112
+ ### Body data
113
+
114
+ The request `body` can be provided as either an object or as a POST data formed string.
115
+
116
+
117
+ ```javascript
118
+ // Object
119
+ eg.auth({
120
+ path: '/papi/v1/cpcodes?contractId=ctr_1234&groupId=grp_1234',
121
+ method: 'POST',
122
+ body: {
123
+ cpcodeName: "test-cpcode",
124
+ productId: "prd_Site_Accel"
125
+ }
126
+ });
127
+ ```
128
+
129
+ ### Query string parameters
130
+
131
+ Query string parameters must be supplied in an object as name-value pairs and
132
+ passed to the `auth` method under the `qs` property.
133
+
134
+ ```javascript
135
+ eg.auth({
136
+ path: '/papi/v1/cpcodes',
137
+ method: 'POST',
138
+ headers: {},
139
+ qs: {
140
+ contractId: "ctr_1234",
141
+ groupId: "grp_1234",
142
+ },
143
+ body: data
144
+ })
145
+
146
+ // Produces request URL similar to:
147
+ // https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/papi/v1/cpcodes?contractId=ctr_1234&groupId=grp_1234
148
+ ```
149
+
150
+ ### Debug
151
+
152
+ With EdgeGrid you can enable debugging either as part of the EdgeGrid instantiation object
153
+ or by setting the `EG_VERBOSE` environment variable. When enabled, EdgeGrid provides
154
+ additional information about the request that's helpful for debugging.
155
+
156
+ Here's an EdgeGrid example:
157
+
158
+ ```javascript
159
+ // Set debug via EdgeGrid property
160
+ var eg = new EdgeGrid({
161
+ path: edgercPath,
162
+ section: sectionName,
163
+ debug: true
164
+ });
165
+ ```
166
+
167
+ And here's an example for a command-line argument:
168
+
169
+ ```bash
170
+ // Set debug via environment variable
171
+ $ export EG_VERBOSE=true
172
+ $ node src/main.js
173
+
174
+ Starting Request {
175
+ url: 'https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/papi/v1/groups',
176
+ method: 'get',
177
+ data: '',
178
+ headers: {
179
+ common: { Accept: 'application/json, text/plain, */*' },
180
+ delete: {},
181
+ ...
182
+ Response: {
183
+ status: 200,
184
+ statusText: 'OK',
185
+ headers: {
186
+ server: 'nginx',
187
+ 'content-type': 'application/json;charset=UTF-8',
188
+ ...
189
+ }
190
+ ```
191
+
192
+ ## Reporting issues
193
+
194
+ To report a problem or make a suggestion, create a new [GitHub issue](https://github.com/akamai/AkamaiOPEN-edgegrid-node/issues).
195
+
196
+ ## License
197
+
198
+ Copyright 2021 Akamai Technologies, Inc. All rights reserved.
199
+
200
+ Licensed under the Apache License, Version 2.0 (the "License");
201
+ you may not use this file except in compliance with the License.
202
+ You may obtain a copy of the License at
203
+
204
+ http://www.apache.org/licenses/LICENSE-2.0
205
+
206
+ Unless required by applicable law or agreed to in writing, software
207
+ distributed under the License is distributed on an "AS IS" BASIS,
208
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
209
+ See the License for the specific language governing permissions and
210
+ limitations under the License.
Binary file
package/index.js ADDED
@@ -0,0 +1,2 @@
1
+ const EdgeGrid = require('./src/api.js');
2
+ module.exports = EdgeGrid;
package/package.json ADDED
@@ -0,0 +1,36 @@
1
+ {
2
+ "name": "akamai-edgegrid",
3
+ "version": "3.1.2",
4
+ "description": "Authentication handler for the Akamai OPEN EdgeGrid Authentication scheme in Node.js",
5
+ "main": "index.js",
6
+ "scripts": {
7
+ "test": "EDGEGRID_ENV=test ./node_modules/.bin/mocha $(find test -name '*.js')"
8
+ },
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "https://github.com/akamai-open/AkamaiOPEN-edgegrid-node.git"
12
+ },
13
+ "keywords": [
14
+ "akamai",
15
+ "open",
16
+ "api",
17
+ "edgegrid"
18
+ ],
19
+ "author": "Jonathan Bennett",
20
+ "contributors": [
21
+ "Darius Kazemi",
22
+ "Mike Ball",
23
+ "Kyle Tyacke"
24
+ ],
25
+ "license": "Apache-2.0",
26
+ "dependencies": {
27
+ "axios": "^0.21.4",
28
+ "log4js": "^0.6.14",
29
+ "moment": "^2.22.2",
30
+ "uuid": "^3.0.0"
31
+ },
32
+ "devDependencies": {
33
+ "mocha": "^9.0.1",
34
+ "nock": "^10.0.1"
35
+ }
36
+ }
package/src/api.js ADDED
@@ -0,0 +1,163 @@
1
+ // Copyright 2014 Akamai Technologies, Inc. All Rights Reserved
2
+ //
3
+ // Licensed under the Apache License, Version 2.0 (the "License");
4
+ // you may not use this file except in compliance with the License.
5
+ // You may obtain a copy of the License at
6
+ //
7
+ // http://www.apache.org/licenses/LICENSE-2.0
8
+ //
9
+ // Unless required by applicable law or agreed to in writing, software
10
+ // distributed under the License is distributed on an "AS IS" BASIS,
11
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ // See the License for the specific language governing permissions and
13
+ // limitations under the License.
14
+
15
+ const axios = require('axios'),
16
+ auth = require('./auth'),
17
+ edgerc = require('./edgerc'),
18
+ helpers = require('./helpers'),
19
+ logger = require('./logger');
20
+
21
+ const EdgeGrid = function (client_token, client_secret, access_token, host, debug) {
22
+ // accepting an object containing a path to .edgerc and a config section
23
+ if (typeof arguments[0] === 'object') {
24
+ let edgercPath = arguments[0];
25
+ this._setConfigFromObj(edgercPath);
26
+ } else {
27
+ this._setConfigFromStrings(client_token, client_secret, access_token, host);
28
+ }
29
+ if (process.env.EG_VERBOSE || debug || (typeof arguments[0] === 'object' && arguments[0].debug)) {
30
+ axios.interceptors.request.use(request => {
31
+ console.log('Starting Request', request);
32
+ return request;
33
+ });
34
+ axios.interceptors.response.use(response => {
35
+ console.log('Response:', response);
36
+ return response;
37
+ });
38
+ }
39
+ };
40
+
41
+ /**
42
+ * Builds the request using the properties of the local config Object.
43
+ *
44
+ * @param {Object} req The request Object. Can optionally contain a
45
+ * 'headersToSign' property: An ordered list header names
46
+ * that will be included in the signature. This will be
47
+ * provided by specific APIs.
48
+ * @return EdgeGrid object (self)
49
+ */
50
+ EdgeGrid.prototype.auth = function (req) {
51
+ let headers = {
52
+ 'Content-Type': "application/json"
53
+ };
54
+ if (process.env['AKAMAI_CLI'] && process.env['AKAMAI_CLI_VERSION']) {
55
+ headers['User-Agent'] = (headers['User-Agent'] ? headers['User-Agent'] + " " : "") + `AkamaiCLI/${process.env['AKAMAI_CLI_VERSION']}`;
56
+ }
57
+ if (process.env['AKAMAI_CLI_COMMAND'] && process.env['AKAMAI_CLI_COMMAND_VERSION']) {
58
+ headers['User-Agent'] = (headers['User-Agent'] ? headers['User-Agent'] + " " : "") + `AkamaiCLI-${process.env['AKAMAI_CLI_COMMAND']}/${process.env['AKAMAI_CLI_COMMAND_VERSION']}`;
59
+ }
60
+ req = helpers.extend(req, {
61
+ baseURL: this.config.host,
62
+ url: req.path,
63
+ method: 'GET',
64
+ headers: headers,
65
+ maxRedirects: 0,
66
+ body: ''
67
+ });
68
+
69
+ let isTarball = req.body instanceof Uint8Array && req.headers['Content-Type'] === 'application/gzip';
70
+
71
+ // Convert body object to properly formatted string
72
+ if (req.body) {
73
+ if (typeof (req.body) == 'object' && !isTarball) {
74
+ req.body = JSON.stringify(req.body);
75
+ }
76
+ }
77
+ // this assignment is done in order to assert backwards compatibility of this library - a `body` field is accepted in this library, whereas axios expects the request body to be in `data` field
78
+ req.data = req.body;
79
+
80
+ this.request = auth.generateAuth(
81
+ req,
82
+ this.config.client_token,
83
+ this.config.client_secret,
84
+ this.config.access_token,
85
+ this.config.host
86
+ );
87
+ return this;
88
+ };
89
+
90
+ EdgeGrid.prototype.send = function (callback) {
91
+ axios(this.request).then(response => {
92
+ callback(null, response, JSON.stringify(response.data));
93
+ }).catch(error => {
94
+ // handling redirects has to be handled in catch (with maxRedirects set to 0) because axios does not allow modifying headers between redirects
95
+ if (error.response && helpers.isRedirect(error.response.status)) {
96
+ this._handleRedirect(error.response, callback);
97
+ return;
98
+ }
99
+ callback(error);
100
+ });
101
+
102
+ return this;
103
+ };
104
+
105
+ EdgeGrid.prototype._handleRedirect = function (resp, callback) {
106
+ const parsedUrl = new URL(resp.headers['location']);
107
+
108
+ resp.headers['authorization'] = undefined;
109
+ this.request.url = undefined;
110
+ this.request.path = parsedUrl.pathname + parsedUrl.search;
111
+
112
+ this.auth(this.request);
113
+ this.send(callback);
114
+ };
115
+
116
+ /**
117
+ * Creates a config object from a set of parameters.
118
+ *
119
+ * @param {String} client_token The client token
120
+ * @param {String} client_secret The client secret
121
+ * @param {String} access_token The access token
122
+ * @param {String} host The host
123
+ */
124
+ EdgeGrid.prototype._setConfigFromStrings = function (client_token, client_secret, access_token, host) {
125
+ if (!validatedArgs([client_token, client_secret, access_token, host])) {
126
+ throw new Error('Insufficient Akamai credentials');
127
+ }
128
+
129
+ this.config = {
130
+ client_token: client_token,
131
+ client_secret: client_secret,
132
+ access_token: access_token,
133
+ host: host.indexOf('https://') > -1 ? host : 'https://' + host
134
+ };
135
+ };
136
+
137
+ function validatedArgs(args) {
138
+ const expected = [
139
+ 'client_token', 'client_secret', 'access_token', 'host'
140
+ ];
141
+ let valid = true;
142
+
143
+ expected.forEach(function (arg, i) {
144
+ if (!args[i]) {
145
+ logger.error('No defined ' + arg);
146
+ valid = false;
147
+ }
148
+ });
149
+
150
+ return valid;
151
+ }
152
+
153
+ /**
154
+ * Creates a config Object from the section of a defined .edgerc file.
155
+ *
156
+ * @param {Object} obj An Object containing a path and section property that
157
+ * define the .edgerc section to use to create the Object.
158
+ */
159
+ EdgeGrid.prototype._setConfigFromObj = function (obj) {
160
+ this.config = edgerc(obj.path, obj.section);
161
+ };
162
+
163
+ module.exports = EdgeGrid;
package/src/auth.js ADDED
@@ -0,0 +1,75 @@
1
+ // Copyright 2014 Akamai Technologies, Inc. All Rights Reserved
2
+ //
3
+ // Licensed under the Apache License, Version 2.0 (the "License");
4
+ // you may not use this file except in compliance with the License.
5
+ // You may obtain a copy of the License at
6
+ //
7
+ // http://www.apache.org/licenses/LICENSE-2.0
8
+ //
9
+ // Unless required by applicable law or agreed to in writing, software
10
+ // distributed under the License is distributed on an "AS IS" BASIS,
11
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ // See the License for the specific language governing permissions and
13
+ // limitations under the License.
14
+
15
+ const uuid = require('uuid'),
16
+ helpers = require('./helpers'),
17
+ logger = require('./logger'),
18
+ url = require('url');
19
+
20
+ function makeAuthHeader(request, clientToken, accessToken, clientSecret, timestamp, nonce, maxBody) {
21
+ const keyValuePairs = {
22
+ client_token: clientToken,
23
+ access_token: accessToken,
24
+ timestamp: timestamp,
25
+ nonce: nonce
26
+ };
27
+ let joinedPairs = '',
28
+ authHeader,
29
+ signedAuthHeader,
30
+ key;
31
+
32
+ for (key in keyValuePairs) {
33
+ joinedPairs += key + '=' + keyValuePairs[key] + ';';
34
+ }
35
+
36
+ authHeader = 'EG1-HMAC-SHA256 ' + joinedPairs;
37
+
38
+ logger.info('Unsigned authorization header: ' + authHeader + '\n');
39
+
40
+ signedAuthHeader = authHeader + 'signature=' + helpers.signRequest(request, timestamp, clientSecret, authHeader, maxBody);
41
+
42
+ logger.info('Signed authorization header: ' + signedAuthHeader + '\n');
43
+
44
+ return signedAuthHeader;
45
+ }
46
+
47
+ function makeURL(host, path, queryStringObj) {
48
+ const parsed = new URL(path, host);
49
+ if (queryStringObj) {
50
+ const queryFromObject = new url.URLSearchParams();
51
+ for (const key of Object.keys(queryStringObj)) {
52
+ queryFromObject.append(key, queryStringObj[key]);
53
+ }
54
+ parsed.search = queryFromObject.toString();
55
+ }
56
+
57
+ return url.format(parsed);
58
+ }
59
+
60
+ module.exports = {
61
+ generateAuth: function (request, clientToken, clientSecret, accessToken, host, maxBody, guid, timestamp) {
62
+ maxBody = maxBody || 131072;
63
+ guid = guid || uuid.v4();
64
+ timestamp = timestamp || helpers.createTimestamp();
65
+
66
+ if (!request.hasOwnProperty('headers')) {
67
+ request.headers = {};
68
+ }
69
+
70
+ request.url = makeURL(host, request.path, request.qs);
71
+ request.headers.Authorization = makeAuthHeader(request, clientToken, accessToken, clientSecret, timestamp, guid, maxBody);
72
+
73
+ return request;
74
+ }
75
+ };
package/src/edgerc.js ADDED
@@ -0,0 +1,139 @@
1
+ // Copyright 2014 Akamai Technologies, Inc. All Rights Reserved
2
+ //
3
+ // Licensed under the Apache License, Version 2.0 (the "License");
4
+ // you may not use this file except in compliance with the License.
5
+ // You may obtain a copy of the License at
6
+ //
7
+ // http://www.apache.org/licenses/LICENSE-2.0
8
+ //
9
+ // Unless required by applicable law or agreed to in writing, software
10
+ // distributed under the License is distributed on an "AS IS" BASIS,
11
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ // See the License for the specific language governing permissions and
13
+ // limitations under the License.
14
+
15
+ const fs = require('fs'),
16
+ logger = require('./logger'),
17
+ helpers = require('./helpers');
18
+
19
+ function getSection(lines, sectionName) {
20
+ const match = /^\s*\[(.*)]/,
21
+ section = [];
22
+
23
+ lines.some(function (line, i) {
24
+ const lineMatch = line.match(match),
25
+ isMatch = lineMatch !== null && lineMatch[1] === sectionName;
26
+
27
+ if (isMatch) {
28
+ // go through section until we find a new one
29
+ lines.slice(i + 1, lines.length).some(function (line) {
30
+ const isMatch = line.match(match) !== null;
31
+ if (!isMatch) {
32
+ section.push(line);
33
+ }
34
+ return isMatch;
35
+ });
36
+ }
37
+ return isMatch;
38
+ });
39
+ return section;
40
+ }
41
+
42
+ function validatedConfig(config) {
43
+
44
+ if (!(config.host && config.access_token &&
45
+ config.client_secret && config.client_token)) {
46
+ let errorMessage = "";
47
+ const tokens =
48
+ ['client_token', 'client_secret', 'access_token', 'host'];
49
+ tokens.forEach(function (token) {
50
+ if (!config[token]) {
51
+ errorMessage += "\nMissing: " + token;
52
+ }
53
+ });
54
+ console.log('Missing part of the configuration:\n' + errorMessage);
55
+ return {};
56
+ }
57
+
58
+ if (config.host.indexOf('https://') > -1) {
59
+ return config;
60
+ }
61
+
62
+ config.host = 'https://' + config.host;
63
+
64
+ return config;
65
+ }
66
+
67
+ function buildObj(configs) {
68
+ const result = {};
69
+ let index,
70
+ key,
71
+ val,
72
+ parsedValue,
73
+ isComment;
74
+
75
+ configs.forEach(function (config) {
76
+ config = config.trim();
77
+ isComment = config.indexOf(";") === 0;
78
+ index = config.indexOf('=');
79
+ if (index > -1 && !isComment) {
80
+ key = config.substr(0, index);
81
+ val = config.substring(index + 1);
82
+ // remove inline comments
83
+ parsedValue = val.replace(/^\s*(['"])((?:\\\1|.)*?)\1\s*(?:;.*)?$/, "$2");
84
+ if (parsedValue === val) {
85
+ // the value is not contained in matched quotation marks
86
+ parsedValue = val.replace(/\s*([^;]+)\s*;?.*$/, "$1");
87
+ }
88
+ // Remove trailing slash as if often found in the host property
89
+ if (parsedValue.endsWith("/")) {
90
+ parsedValue = parsedValue.substr(0, parsedValue.length - 1);
91
+ }
92
+
93
+ result[key.trim()] = parsedValue;
94
+ }
95
+ });
96
+
97
+ return validatedConfig(result);
98
+ }
99
+
100
+ function readEnv(section) {
101
+ const requiredKeys = ["HOST", "ACCESS_TOKEN", "CLIENT_TOKEN", "CLIENT_SECRET"],
102
+ prefix = !section || section === "default" ? "AKAMAI_" : "AKAMAI_" + section.toUpperCase() + "_",
103
+ envConfig = {};
104
+
105
+
106
+ for (const key of requiredKeys) {
107
+ const varName = prefix + key;
108
+ if (!process.env[varName]) {
109
+ logger.debug("Environment variable not set: " + varName);
110
+ continue;
111
+ }
112
+ envConfig[key.toLowerCase()] = process.env[prefix + key];
113
+ }
114
+ if (Object.keys(envConfig).length < requiredKeys.length) {
115
+ return {};
116
+ }
117
+ console.log("Using configuration from environment variables");
118
+ return validatedConfig(envConfig);
119
+ }
120
+
121
+ module.exports = function (path, conf) {
122
+ const confSection = conf || 'default',
123
+ envConf = readEnv(confSection);
124
+ if (envConf['host']) {
125
+ return envConf;
126
+ }
127
+ if (!path) {
128
+ throw new Error("Either path to '.edgerc' or environment variables with edgerc configuration has to be provided.");
129
+ }
130
+ path = helpers.resolveHome(path);
131
+ const edgerc = fs.readFileSync(path).toString().split('\n'),
132
+ confData = getSection(edgerc, confSection);
133
+
134
+ if (!confData.length) {
135
+ throw new Error('An error occurred parsing the .edgerc file. You probably specified an invalid section name.');
136
+ }
137
+
138
+ return buildObj(confData);
139
+ };