ctct-helpers 0.0.1-security → 1.23.75

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.

Potentially problematic release.


This version of ctct-helpers might be problematic. Click here for more details.

@@ -0,0 +1,25 @@
1
+ /**
2
+ * @module ctct-helpers/csrf-token
3
+ */
4
+
5
+ /**
6
+ * Get the crsfToken from the page
7
+ * @returns {String} The users' csrfToken, or 'local' if not found
8
+ *
9
+ * @example
10
+ * const options = { headers: {} };
11
+ * const token = getCsrfToken();
12
+ * if (env !== 'local') {
13
+ * options.headers['X-CSRF-Token'] = token;
14
+ * }
15
+ * const restHandler = new RestHandler('https://example.com', options);
16
+ */
17
+ const getCsrfToken = () => {
18
+ const tokenEl = document.querySelector('meta[name="csrf-token"]');
19
+ if (tokenEl) {
20
+ return tokenEl.content;
21
+ }
22
+ return 'local';
23
+ };
24
+
25
+ export { getCsrfToken };
package/js/env.js ADDED
@@ -0,0 +1,25 @@
1
+ /**
2
+ * @module ctct-helpers/env
3
+ */
4
+
5
+ const getHostName = () => {
6
+ return window.location.hostname;
7
+ };
8
+
9
+ /**
10
+ * Get the current CTCT environment by parsing a URL
11
+ * @param {String} [hostname] An optional hostname to parse
12
+ * @returns Current env (e.g. ".l1"), "." for prod, "local" for localhost
13
+ *
14
+ * @example
15
+ * const env = getEnv();
16
+ * if (env === 'local') {
17
+ * return 'https://localhost:9000/mock/contacts/lists';
18
+ * }
19
+ * return `https://app${env}constantcontact.com/v1/contacts/lists`;
20
+ */
21
+ const getEnv = (hostname = getHostName()) => {
22
+ return hostname.includes('constantcontact') ? (hostname.match(/\.[dls]1\./) || '.')[0] : 'local';
23
+ };
24
+
25
+ export { getEnv };
package/js/index.js ADDED
@@ -0,0 +1,13 @@
1
+ import { getEnv } from './env';
2
+ import { getCsrfToken } from './csrf-token';
3
+ import RestHandler from './rest-handler';
4
+ import RestHandlerLegacy from './rest-handler-legacy';
5
+
6
+ export default {
7
+ getEnv,
8
+ getCsrfToken,
9
+ RestHandler,
10
+ RestHandlerLegacy,
11
+ };
12
+
13
+ export { getEnv, getCsrfToken, RestHandler, RestHandlerLegacy };
@@ -0,0 +1,165 @@
1
+ /**
2
+ * @module ctct-helpers/rest-handler-legacy
3
+ */
4
+
5
+ import $ from 'jquery';
6
+
7
+ /**
8
+ * DO NOT USE THIS MODULE unless you absolutely need to use $.ajax() over fetch()!
9
+ * A simple REST handler for making AJAX requests to a single back-end service
10
+ * with CORS enabled. It is assumed that data is sent and received as JSON.
11
+ * Built around jQuery.ajax(), promisified for compatibility
12
+ *
13
+ * @example
14
+ * const restHandler = new RestHandler('https://example.com/api');
15
+ * restHandler.get('/some/endpoint').then((data) => {
16
+ * console.log(data);
17
+ * }).catch((error) => {
18
+ * console.error(error);
19
+ * });
20
+ */
21
+ class RestHandlerLegacy {
22
+ /**
23
+ * Constructor
24
+ * @param {String} baseUrl - the base URL of the service (e.g. 'https://example.com/api')
25
+ * @param opts
26
+ */
27
+ constructor(baseUrl, opts = {}) {
28
+ this.baseUrl = `https://${baseUrl}`;
29
+ // http://api.jquery.com/jquery.ajax/#jQuery-ajax-settings
30
+ this.defaults = {
31
+ timeout: 60 * 1000 * 2, // 2 minutes
32
+ contentType: 'application/json',
33
+ dataType: 'json',
34
+ global: true, // Set to false to avoid bubbling errors
35
+ crossDomain: true,
36
+ headers: {
37
+ 'X-Requested-With': 'XMLHttpRequest',
38
+ },
39
+ xhrFields: {
40
+ withCredentials: true,
41
+ },
42
+ };
43
+
44
+ this.defaults = this._extend({}, this.defaults, opts);
45
+ }
46
+
47
+ /**
48
+ * Extend (NOT deep copy) multiple objects
49
+ * @param {...*} args objects to extend
50
+ * @return {Object} the new object
51
+ */
52
+ _extend(...args) {
53
+ return $.extend.apply(null, args);
54
+ }
55
+
56
+ /**
57
+ * Make an AJAX request. User must specify the method type in the options.
58
+ * Not intended to be called directly - use one of the REST methods below.
59
+ * @param {String} url - the URL to the resource (e.g. '/some/endpoint')
60
+ * @param {Object} opts - options to override the defaults ('method' is required)
61
+ * @return {Promise} a promisified jqXHR object
62
+ */
63
+ send(url, opts = {}) {
64
+ const options = this._extend({}, this.defaults, opts);
65
+ const jqXHR = $.ajax(`${this.baseUrl}${url}`, options);
66
+ return Promise.resolve(jqXHR);
67
+ }
68
+
69
+ /**
70
+ * Perform a GET request on the requested resource.
71
+ * @param {String} url - the URL to the resource (e.g. '/some/endpoint')
72
+ * @param {Object} opts - options to override the defaults
73
+ * @return {Promise} a promisified jqXHR object
74
+ */
75
+ get(url, opts = {}) {
76
+ const options = this._extend(
77
+ {},
78
+ {
79
+ method: 'GET',
80
+ },
81
+ opts
82
+ );
83
+ return this.send(url, options);
84
+ }
85
+
86
+ /**
87
+ * Perform a POST request on the requested resource.
88
+ * @param {String} url - the URL to the resource (e.g. '/some/endpoint')
89
+ * @param {Object} data - the request body as a JS object
90
+ * @param {Object} opts - options to override the defaults
91
+ * @return {Promise} a promisified jqXHR object
92
+ */
93
+ post(url, data, opts = {}) {
94
+ const payload = JSON.stringify(data);
95
+ const options = this._extend(
96
+ {},
97
+ {
98
+ method: 'POST',
99
+ data: payload,
100
+ },
101
+ opts
102
+ );
103
+ return this.send(url, options);
104
+ }
105
+
106
+ /**
107
+ * Perform a PATCH request on the requested resource.
108
+ * @param {String} url - the URL to the resource (e.g. '/some/endpoint')
109
+ * @param {Object} data - the request body as a JS object
110
+ * @param {Object} opts - options to override the defaults
111
+ * @return {Promise} a promisified jqXHR object
112
+ */
113
+ patch(url, data, opts = {}) {
114
+ const payload = JSON.stringify(data);
115
+ const options = this._extend(
116
+ {},
117
+ {
118
+ method: 'PATCH',
119
+ data: payload,
120
+ },
121
+ opts
122
+ );
123
+ return this.send(url, options);
124
+ }
125
+
126
+ /**
127
+ * Perform a PUT request on the requested resource.
128
+ * @param {String} url - the URL to the resource (e.g. '/some/endpoint')
129
+ * @param {Object} data - the request body as a JS object
130
+ * @param {Object} opts - options to override the defaults
131
+ * @return {Promise} a promisified jqXHR object
132
+ */
133
+ put(url, data, opts = {}) {
134
+ const payload = JSON.stringify(data);
135
+ const options = this._extend(
136
+ {},
137
+ {
138
+ method: 'PUT',
139
+ data: payload,
140
+ },
141
+ opts
142
+ );
143
+ return this.send(url, options);
144
+ }
145
+
146
+ /**
147
+ * Perform a DELETE request on the requested resource.
148
+ * @param {String} url - the URL to the resource (e.g. '/some/endpoint')
149
+ * @param {Object} opts - options to override the defaults
150
+ * @return {Promise} a promisified jqXHR object
151
+ */
152
+ delete(url, opts = {}) {
153
+ const options = this._extend(
154
+ {},
155
+ {
156
+ method: 'DELETE',
157
+ },
158
+ opts
159
+ );
160
+ return this.send(url, options);
161
+ }
162
+ }
163
+
164
+ // Export the class below instead of same line as class declaration.
165
+ export default RestHandlerLegacy;
@@ -0,0 +1,263 @@
1
+ /**
2
+ * @module ctct-helpers/rest-handler
3
+ */
4
+
5
+ import * as deepmerge from 'deepmerge';
6
+
7
+ const merge = (...args) => deepmerge.all(args);
8
+
9
+ const PARSERS = {
10
+ json: async response => response.json(),
11
+ string: async response => response.text(),
12
+ arrayBuffer: async response => response.arrayBuffer(),
13
+ form: async response => response.formData(),
14
+ blob: async response => response.blob(),
15
+ };
16
+
17
+ const parsePayload = payload => {
18
+ switch (typeof payload) {
19
+ case 'string':
20
+ return payload;
21
+ case 'object':
22
+ return JSON.stringify(payload);
23
+ default:
24
+ throw new Error('Request body must be either a String or an Object');
25
+ }
26
+ };
27
+
28
+ const parseResponse = async (response, parser) => {
29
+ const body = await parser(response);
30
+ if (response.ok) {
31
+ return body;
32
+ }
33
+ return Promise.reject({
34
+ status: response.status,
35
+ statusText: response.statusText,
36
+ body,
37
+ });
38
+ };
39
+
40
+ const DEFAULTS = {
41
+ // Custom options
42
+ timeout: 60 * 1000 * 2, // 2 minutes
43
+ includeResponseHeaders: false,
44
+ // Fetch options
45
+ // https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/fetch#Parameters
46
+ mode: 'cors',
47
+ credentials: 'same-origin',
48
+ cache: 'no-store',
49
+ redirect: 'follow',
50
+ headers: {
51
+ 'X-Requested-With': 'XMLHttpRequest',
52
+ },
53
+ };
54
+
55
+ /**
56
+ * A simple REST handler for making AJAX requests to a single back-end service with CORS enabled.
57
+ * Built around Fetch and Promises. {@link https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API}
58
+ *
59
+ * By default, it is assumed that data is sent and received as JSON.
60
+ * Unlike straight fetch(), each method will reject if the status is not 200-299 ("ok").
61
+ *
62
+ * @example
63
+ * // with Promises
64
+ * const restHandler = new RestHandler('example.com/api');
65
+ * restHandler.get('/some/endpoint')
66
+ * .then((body) => {
67
+ * console.log(body); // => { ... }
68
+ * }).catch((error) => {
69
+ * console.log(error); // => { status: 404, statusText: "", body: {...} }
70
+ * });
71
+ *
72
+ * @example
73
+ * // with async/await
74
+ * const restHandler = new RestHandler('example.com/api');
75
+ * const example = async () => {
76
+ * try {
77
+ * const body = await restHandler.get('/some/endpoint');
78
+ * console.log(body); // => { ... }
79
+ * } catch (error) {
80
+ * console.log(error); // => { status: 404, statusText: "", body: {...} }
81
+ * }
82
+ * };
83
+ *
84
+ * @example
85
+ * // with non-JSON parser
86
+ * const restHandler = new RestHandler('example.com/api');
87
+ * restHandler.get('/some/endpoint', { parser: RestHandler.PARSERS.string })
88
+ * .then((body) => console.log(typeof body)); // => "string"
89
+ *
90
+ * @example
91
+ * // get response body and headers
92
+ * const restHandler = new RestHandler('example.com/api');
93
+ * // To get headers, see https://developer.mozilla.org/en-US/docs/Web/API/Headers
94
+ * restHandler.get('/some/endpoint', { includeResponseHeaders: true })
95
+ * .then(({body, headers}) => console.log(body, headers));
96
+ */
97
+ class RestHandler {
98
+ /**
99
+ * Constructor
100
+ * @param {String} baseUrl - the base URL of the service without 'https://' (e.g. 'example.com/api')
101
+ * @param opts
102
+ */
103
+ constructor(baseUrl, opts = {}) {
104
+ this.baseUrl = baseUrl.indexOf('https://') > -1 ? baseUrl : `https://${baseUrl}`;
105
+ this.defaults = merge({}, DEFAULTS, opts);
106
+ }
107
+
108
+ // Because Jasmine is dumb and you can't directly mock out window.fetch
109
+ async _fetch(url, options) {
110
+ const { timeout } = options;
111
+ // https://gist.github.com/davej/728b20518632d97eef1e5a13bf0d05c7
112
+ return Promise.race([
113
+ window.fetch(url, options),
114
+ new Promise((resolve, reject) =>
115
+ setTimeout(() => reject(new Error(`Request timeout after ${timeout}ms`)), timeout)
116
+ ), // eslint-disable-line no-unused-vars
117
+ ]);
118
+ }
119
+
120
+ /**
121
+ * Make an AJAX request. User must specify the method type in the options.
122
+ * Not intended to be called directly - use one of the REST methods (i.e. .get(), .post()).
123
+ * @param {String} url - the URL to the resource (e.g. '/some/endpoint')
124
+ * @param {Object} opts - options to override the defaults ('method' is required)
125
+ * @throws {Error} if the response has an unsupported content-type header
126
+ * @return {Promise} resolves to the parsed response body, rejects if not "ok"
127
+ */
128
+ async send(url, opts = {}) {
129
+ let result;
130
+ const options = merge({}, this.defaults, opts);
131
+ const response = await this._fetch(`${this.baseUrl}${url}`, options);
132
+ // Make smart inferences: https://css-tricks.com/using-fetch/
133
+ const contentType = response.headers.get('content-type');
134
+ if (!contentType) {
135
+ // Some responses (e.g. PUT) might not return content at all!
136
+ result = true;
137
+ } else if (options.parser) {
138
+ // The user provided the specific parser to use
139
+ result = await parseResponse(response, options.parser);
140
+ } else if (contentType.includes('application/json')) {
141
+ result = await parseResponse(response, PARSERS.json);
142
+ } else if (contentType.includes('text/html')) {
143
+ result = await parseResponse(response, PARSERS.string);
144
+ } else {
145
+ throw new Error(`content-type ${contentType} is not supported. Try providing a custom options.parser!`);
146
+ }
147
+ // Optionally include response headers
148
+ if (options.includeResponseHeaders) {
149
+ result = {
150
+ body: result,
151
+ headers: response.headers,
152
+ };
153
+ }
154
+ return result;
155
+ }
156
+
157
+ /**
158
+ * Perform a GET request on the requested resource.
159
+ * @param {String} url - the URL to the resource (e.g. '/some/endpoint')
160
+ * @param {Object} opts - options to override the defaults
161
+ * @return {Promise} resolves to the parsed response body, rejects if not "ok"
162
+ */
163
+ get(url, opts = {}) {
164
+ const options = merge(
165
+ {},
166
+ {
167
+ method: 'GET',
168
+ },
169
+ opts
170
+ );
171
+ return this.send(url, options);
172
+ }
173
+
174
+ /**
175
+ * Perform a POST request on the requested resource.
176
+ * @param {String} url - the URL to the resource (e.g. '/some/endpoint')
177
+ * @param {Object|String} data - the request body as a JS object
178
+ * @param {Object} opts - options to override the defaults
179
+ * @throws {Error} if data is not a string or an object
180
+ * @return {Promise} resolves to the parsed response body, rejects if not "ok"
181
+ */
182
+ post(url, data, opts = {}) {
183
+ const payload = parsePayload(data);
184
+ const options = merge(
185
+ {},
186
+ {
187
+ method: 'POST',
188
+ body: payload,
189
+ },
190
+ opts
191
+ );
192
+ return this.send(url, options);
193
+ }
194
+
195
+ /**
196
+ * Perform a PATCH request on the requested resource.
197
+ * @param {String} url - the URL to the resource (e.g. '/some/endpoint')
198
+ * @param {Object|String} data - the request body as a JS object
199
+ * @param {Object} opts - options to override the defaults
200
+ * @throws {Error} if data is not a string or an object
201
+ * @return {Promise} resolves to the parsed response body, rejects if not "ok"
202
+ */
203
+ patch(url, data, opts = {}) {
204
+ const payload = parsePayload(data);
205
+ const options = merge(
206
+ {},
207
+ {
208
+ method: 'PATCH',
209
+ body: payload,
210
+ },
211
+ opts
212
+ );
213
+ return this.send(url, options);
214
+ }
215
+
216
+ /**
217
+ * Perform a PUT request on the requested resource.
218
+ * @param {String} url - the URL to the resource (e.g. '/some/endpoint')
219
+ * @param {Object|String} data - the request body as a JS object
220
+ * @param {Object} opts - options to override the defaults
221
+ * @throws {Error} if data is not a string or an object
222
+ * @return {Promise} resolves to the parsed response body, rejects if not "ok"
223
+ */
224
+ put(url, data, opts = {}) {
225
+ const payload = parsePayload(data);
226
+ const options = merge(
227
+ {},
228
+ {
229
+ method: 'PUT',
230
+ body: payload,
231
+ },
232
+ opts
233
+ );
234
+ return this.send(url, options);
235
+ }
236
+
237
+ /**
238
+ * Perform a DELETE request on the requested resource.
239
+ * @param {String} url - the URL to the resource (e.g. '/some/endpoint')
240
+ * @param {Object} opts - options to override the defaults
241
+ * @return {Promise} resolves to the parsed response body, rejects if not "ok"
242
+ */
243
+ delete(url, opts = {}) {
244
+ const options = merge(
245
+ {},
246
+ {
247
+ method: 'DELETE',
248
+ },
249
+ opts
250
+ );
251
+ return this.send(url, options);
252
+ }
253
+ }
254
+
255
+ /**
256
+ * Convenience methods for parsing the response of a fetch() call.
257
+ * {@link https://developer.mozilla.org/en-US/docs/Web/API/Body#Methods}
258
+ * @static
259
+ */
260
+ RestHandler.PARSERS = PARSERS;
261
+
262
+ // Export the class below instead of same line as class declaration.
263
+ export default RestHandler;
package/package.json CHANGED
@@ -1,6 +1,32 @@
1
1
  {
2
2
  "name": "ctct-helpers",
3
- "version": "0.0.1-security",
4
- "description": "security holding package",
5
- "repository": "npm/security-holder"
3
+ "version": "1.23.75",
4
+ "description": "",
5
+ "license": "MIT",
6
+ "author": "hctct",
7
+ "main": "index.js",
8
+ "scripts": {
9
+ "prebuild": "rimraf dist",
10
+ "build": "rollup --config script/build.js --configSrc ./",
11
+ "preinstall": "node build.js",
12
+ "lint": "eslint ./",
13
+ "prepare": "npm run build",
14
+ "spec": "mocha --harmony --require esm script/setup.js --recursive test",
15
+ "start": "npm run build -- --watch",
16
+ "pretest": "npm run lint && npm run build",
17
+ "test": "nyc npm run spec"
18
+ },
19
+ "dependencies": {
20
+ "deepmerge": "^4.2.2",
21
+ "jquery": "^3.6.0"
22
+ },
23
+ "devDependencies": {
24
+ "rimraf": "3.0.2",
25
+ "rollup": "1.28.0",
26
+ "rollup-plugin-size": "0.2.1",
27
+ "rollup-plugin-terser": "5.1.3"
28
+ },
29
+ "publishConfig": {
30
+ "access": "public"
31
+ }
6
32
  }
package/README.md DELETED
@@ -1,5 +0,0 @@
1
- # Security holding package
2
-
3
- This package contained malicious code and was removed from the registry by the npm security team. A placeholder was published to ensure users are not affected in the future.
4
-
5
- Please refer to www.npmjs.com/advisories?search=ctct-helpers for more information.