@usebruno/filestore 0.1.0 → 0.2.0

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.
Files changed (30) hide show
  1. package/dist/cjs/formats/bru/utils/oauth2-additional-params.d.ts +38 -0
  2. package/dist/cjs/formats/bru/utils/request-parse-and-redact-body-data.d.ts +9 -0
  3. package/dist/cjs/index.d.ts +1 -0
  4. package/dist/cjs/index.js +1 -1
  5. package/dist/cjs/index.js.map +1 -1
  6. package/dist/cjs/workers/formats/bru/utils/oauth2-additional-params.d.ts +38 -0
  7. package/dist/cjs/workers/formats/bru/utils/request-parse-and-redact-body-data.d.ts +9 -0
  8. package/dist/cjs/workers/index.d.ts +1 -0
  9. package/dist/cjs/workers/worker-script.js +1 -1
  10. package/dist/cjs/workers/worker-script.js.map +1 -1
  11. package/dist/esm/formats/bru/utils/oauth2-additional-params.d.ts +38 -0
  12. package/dist/esm/formats/bru/utils/request-parse-and-redact-body-data.d.ts +9 -0
  13. package/dist/esm/index.d.ts +1 -0
  14. package/dist/esm/index.js +1 -1
  15. package/dist/esm/index.js.map +1 -1
  16. package/dist/esm/workers/formats/bru/utils/oauth2-additional-params.d.ts +38 -0
  17. package/dist/esm/workers/formats/bru/utils/request-parse-and-redact-body-data.d.ts +9 -0
  18. package/dist/esm/workers/index.d.ts +1 -0
  19. package/dist/esm/workers/worker-script.js +1 -1
  20. package/dist/esm/workers/worker-script.js.map +1 -1
  21. package/package.json +2 -2
  22. package/src/formats/bru/index.ts +132 -40
  23. package/src/formats/bru/tests/fixtures/oauth2-additional-params.js +116 -0
  24. package/src/formats/bru/tests/fixtures/request-parse-and-redact-body-data/input.bru +66 -0
  25. package/src/formats/bru/tests/fixtures/request-parse-and-redact-body-data/output.bru +35 -0
  26. package/src/formats/bru/tests/oauth2-additional-params.spec.js +45 -0
  27. package/src/formats/bru/tests/request-parse-and-redact-body-data.spec.js +44 -0
  28. package/src/formats/bru/utils/oauth2-additional-params.ts +141 -0
  29. package/src/formats/bru/utils/request-parse-and-redact-body-data.ts +77 -0
  30. package/src/index.ts +8 -0
@@ -0,0 +1,116 @@
1
+ const getBruJsonWithAdditionalParams = (grantType) => ({
2
+ "meta": {
3
+ "name": "OAuth2 Additional Params Test",
4
+ "type": "http",
5
+ "seq": 1
6
+ },
7
+ "http": {
8
+ "method": "get",
9
+ "url": "https://api.usebruno.com/protected"
10
+ },
11
+ "auth": {
12
+ "oauth2": {
13
+ "grantType": grantType,
14
+ },
15
+ },
16
+ "oauth2_additional_parameters_auth_req_headers": [
17
+ {
18
+ "name": "auth-header",
19
+ "value": "auth-header-value",
20
+ "enabled": true
21
+ },
22
+ {
23
+ "name": "disabled-auth-header",
24
+ "value": "disabled-auth-header-value",
25
+ "enabled": false
26
+ }
27
+ ],
28
+ "oauth2_additional_parameters_auth_req_queryparams": [
29
+ {
30
+ "name": "auth-query-param",
31
+ "value": "auth-query-param-value",
32
+ "enabled": true
33
+ },
34
+ {
35
+ "name": "disabled-auth-query-param",
36
+ "value": "disabled-auth-query-param-value",
37
+ "enabled": false
38
+ }
39
+ ],
40
+ "oauth2_additional_parameters_access_token_req_headers": [
41
+ {
42
+ "name": "token-header",
43
+ "value": "token-header-value",
44
+ "enabled": true
45
+ },
46
+ {
47
+ "name": "disabled-token-header",
48
+ "value": "disabled-token-header-value",
49
+ "enabled": false
50
+ }
51
+ ],
52
+ "oauth2_additional_parameters_access_token_req_queryparams": [
53
+ {
54
+ "name": "token-query-param",
55
+ "value": "token-query-param-value",
56
+ "enabled": true
57
+ },
58
+ {
59
+ "name": "disabled-token-query-param",
60
+ "value": "disabled-token-query-param-value",
61
+ "enabled": false
62
+ }
63
+ ],
64
+ "oauth2_additional_parameters_access_token_req_bodyvalues": [
65
+ {
66
+ "name": "token-body",
67
+ "value": "token-body-value",
68
+ "enabled": true
69
+ },
70
+ {
71
+ "name": "disabled-token-body",
72
+ "value": "disabled-token-body-value",
73
+ "enabled": false
74
+ }
75
+ ],
76
+ "oauth2_additional_parameters_refresh_token_req_headers": [
77
+ {
78
+ "name": "refresh-header",
79
+ "value": "refresh-header-value",
80
+ "enabled": true
81
+ },
82
+ {
83
+ "name": "disabled-refresh-header",
84
+ "value": "disabled-refresh-header-value",
85
+ "enabled": false
86
+ }
87
+ ],
88
+ "oauth2_additional_parameters_refresh_token_req_queryparams": [
89
+ {
90
+ "name": "refresh-query-param",
91
+ "value": "refresh-query-param-value",
92
+ "enabled": true
93
+ },
94
+ {
95
+ "name": "disabled-refresh-query-param",
96
+ "value": "disabled-refresh-query-param-value",
97
+ "enabled": false
98
+ }
99
+ ],
100
+ "oauth2_additional_parameters_refresh_token_req_bodyvalues": [
101
+ {
102
+ "name": "refresh-body",
103
+ "value": "refresh-body-value",
104
+ "enabled": true
105
+ },
106
+ {
107
+ "name": "disabled-refresh-body",
108
+ "value": "disabled-refresh-body-value",
109
+ "enabled": false
110
+ }
111
+ ]
112
+ })
113
+
114
+ export {
115
+ getBruJsonWithAdditionalParams
116
+ };
@@ -0,0 +1,66 @@
1
+ meta {
2
+ name: echo request
3
+ type: http
4
+ seq: 1
5
+ }
6
+
7
+ post {
8
+ url: https://echo.usebruno.com
9
+ body: json
10
+ auth: none
11
+ }
12
+ body:json {
13
+ {
14
+ "hello": "world"
15
+ }
16
+ }
17
+
18
+ body:text {
19
+ This is a text body
20
+ }
21
+ body:xml {
22
+ <xml>
23
+ <name>John</name>
24
+ <age>30</age>
25
+ </xml>
26
+ }
27
+
28
+ body:sparql {
29
+ SELECT * WHERE {
30
+ ?subject ?predicate ?object .
31
+ }
32
+ LIMIT 10
33
+ }
34
+ body:graphql {
35
+ {
36
+ launchesPast {
37
+ launch_site {
38
+ site_name
39
+ }
40
+ launch_success
41
+ }
42
+ }
43
+ }
44
+
45
+ body:form-urlencoded {
46
+ apikey: secret
47
+ numbers: +91998877665
48
+ ~message: hello
49
+ }
50
+
51
+ body:multipart-form {
52
+ apikey: secret
53
+ numbers: +91998877665
54
+ ~message: hello
55
+ }
56
+ body:file {
57
+ file: @file(path/to/file.json) @contentType(application/json)
58
+ file: @file(path/to/file.json) @contentType(application/json)
59
+ ~file: @file(path/to/file2.json) @contentType(application/json)
60
+ }
61
+
62
+ body:graphql:vars {
63
+ {
64
+ "limit": 5
65
+ }
66
+ }
@@ -0,0 +1,35 @@
1
+ meta {
2
+ name: echo request
3
+ type: http
4
+ seq: 1
5
+ }
6
+
7
+ post {
8
+ url: https://echo.usebruno.com
9
+ body: json
10
+ auth: none
11
+ }
12
+
13
+ body:form-urlencoded {
14
+ apikey: secret
15
+ numbers: +91998877665
16
+ ~message: hello
17
+ }
18
+
19
+ body:multipart-form {
20
+ apikey: secret
21
+ numbers: +91998877665
22
+ ~message: hello
23
+ }
24
+
25
+ body:file {
26
+ file: @file(path/to/file.json) @contentType(application/json)
27
+ file: @file(path/to/file.json) @contentType(application/json)
28
+ ~file: @file(path/to/file2.json) @contentType(application/json)
29
+ }
30
+
31
+ body:graphql:vars {
32
+ {
33
+ "limit": 5
34
+ }
35
+ }
@@ -0,0 +1,45 @@
1
+ const { getOauth2AdditionalParameters } = require('../utils/oauth2-additional-params');
2
+ const { bruRequestToJson, bruCollectionToJson } = require('../index');
3
+ const { getBruJsonWithAdditionalParams } = require('./fixtures/oauth2-additional-params');
4
+
5
+ describe('getOauth2AdditionalParameters', () => {
6
+ it('authorization_code', () => {
7
+ const additionalParameters = getOauth2AdditionalParameters(getBruJsonWithAdditionalParams('authorization_code'));
8
+ expect(additionalParameters.authorization).toHaveLength(4);
9
+ expect(additionalParameters.token).toHaveLength(6);
10
+ expect(additionalParameters.refresh).toHaveLength(6);
11
+
12
+ expect(additionalParameters.authorization.map(p => p.sendIn).sort()).toEqual(['headers', 'headers', 'queryparams', 'queryparams']);
13
+ expect(additionalParameters.token.map(p => p.sendIn).sort()).toEqual(['body', 'body', 'headers', 'headers', 'queryparams', 'queryparams']);
14
+ expect(additionalParameters.refresh.map(p => p.sendIn).sort()).toEqual(['body', 'body', 'headers', 'headers', 'queryparams', 'queryparams']);
15
+ });
16
+
17
+ it('client_credentials', () => {
18
+ const additionalParameters = getOauth2AdditionalParameters(getBruJsonWithAdditionalParams('client_credentials'));
19
+ expect(additionalParameters.authorization).toBeUndefined();
20
+ expect(additionalParameters.token).toHaveLength(6);
21
+ expect(additionalParameters.refresh).toHaveLength(6);
22
+
23
+ expect(additionalParameters.token.map(p => p.sendIn).sort()).toEqual(['body', 'body', 'headers', 'headers', 'queryparams', 'queryparams']);
24
+ expect(additionalParameters.refresh.map(p => p.sendIn).sort()).toEqual(['body', 'body', 'headers', 'headers', 'queryparams', 'queryparams']);
25
+ });
26
+
27
+ it('password', () => {
28
+ const additionalParameters = getOauth2AdditionalParameters(getBruJsonWithAdditionalParams('password'));
29
+ expect(additionalParameters.authorization).toBeUndefined();
30
+ expect(additionalParameters.token).toHaveLength(6);
31
+ expect(additionalParameters.refresh).toHaveLength(6);
32
+
33
+ expect(additionalParameters.token.map(p => p.sendIn).sort()).toEqual(['body', 'body', 'headers', 'headers', 'queryparams', 'queryparams']);
34
+ expect(additionalParameters.refresh.map(p => p.sendIn).sort()).toEqual(['body', 'body', 'headers', 'headers', 'queryparams', 'queryparams']);
35
+ });
36
+
37
+ it('implicit', () => {
38
+ const additionalParameters = getOauth2AdditionalParameters(getBruJsonWithAdditionalParams('implicit'));
39
+ expect(additionalParameters.authorization).toHaveLength(4);
40
+ expect(additionalParameters.token).toBeUndefined();
41
+ expect(additionalParameters.refresh).toBeUndefined();
42
+
43
+ expect(additionalParameters.authorization.map(p => p.sendIn).sort()).toEqual(['headers', 'headers', 'queryparams', 'queryparams']);
44
+ });
45
+ });
@@ -0,0 +1,44 @@
1
+ const fs = require('node:fs');
2
+ const path = require('node:path');
3
+ const { bruRequestParseAndRedactBodyData } = require("../utils/request-parse-and-redact-body-data");
4
+
5
+ describe("parse and redact body data", () => {
6
+ it("should redact body blocks from the bru file string", () => {
7
+ const fixturesPath = `/fixtures/request-parse-and-redact-body-data`;
8
+ const inputBruString = fs.readFileSync(path.join(__dirname, fixturesPath, './input.bru'), 'utf8');
9
+ const expectedOutputBruString = fs.readFileSync(path.join(__dirname, fixturesPath, './output.bru'), 'utf8');
10
+
11
+ const res = bruRequestParseAndRedactBodyData(inputBruString);
12
+ expect(res.bruFileStringWithRedactedBody).toBe(expectedOutputBruString);
13
+ expect(res.extractedBodyContent).toEqual({
14
+ graphql: `
15
+ {
16
+ launchesPast {
17
+ launch_site {
18
+ site_name
19
+ }
20
+ launch_success
21
+ }
22
+ }
23
+ `.trim(),
24
+ json: `
25
+ {
26
+ "hello": "world"
27
+ }
28
+ `.trim(),
29
+ sparql: `
30
+ SELECT * WHERE {
31
+ ?subject ?predicate ?object .
32
+ }
33
+ LIMIT 10
34
+ `.trim(),
35
+ text: `This is a text body`,
36
+ xml: `
37
+ <xml>
38
+ <name>John</name>
39
+ <age>30</age>
40
+ </xml>
41
+ `.trim()
42
+ })
43
+ });
44
+ });
@@ -0,0 +1,141 @@
1
+ type T_Oauth2ParameterType = 'authorization' | 'token' | 'refresh';
2
+ type T_Oauth2ParameterSendInType = 'headers' | 'queryparams' | 'body';
3
+
4
+ export interface T_OAuth2AdditionalParam {
5
+ name: string;
6
+ value: string;
7
+ enabled: boolean;
8
+ sendIn: T_Oauth2ParameterSendInType
9
+ }
10
+
11
+ export interface T_OAuth2AdditionalParameters {
12
+ authorization?: T_OAuth2AdditionalParam[];
13
+ token?: T_OAuth2AdditionalParam[];
14
+ refresh?: T_OAuth2AdditionalParam[];
15
+ }
16
+
17
+ export interface T_Oauth2Auth {
18
+ grantType: string;
19
+ additionalParameters?: T_OAuth2AdditionalParameters;
20
+ }
21
+
22
+ export interface T_BruJson {
23
+ auth: {
24
+ oauth2: T_Oauth2Auth;
25
+ };
26
+ oauth2_additional_parameters_auth_req_headers?: any[];
27
+ oauth2_additional_parameters_auth_req_queryparams?: any[];
28
+ oauth2_additional_parameters_access_token_req_headers?: any[];
29
+ oauth2_additional_parameters_access_token_req_queryparams?: any[];
30
+ oauth2_additional_parameters_access_token_req_bodyvalues?: any[];
31
+ oauth2_additional_parameters_refresh_token_req_headers?: any[];
32
+ oauth2_additional_parameters_refresh_token_req_queryparams?: any[];
33
+ oauth2_additional_parameters_refresh_token_req_bodyvalues?: any[];
34
+ }
35
+
36
+ interface T_Oauth2ParameterMapping {
37
+ type: T_Oauth2ParameterType;
38
+ sendIn: T_Oauth2ParameterSendInType;
39
+ source: keyof T_BruJson;
40
+ }
41
+
42
+ const PARAMETER_MAPPINGS: T_Oauth2ParameterMapping[] = [
43
+ // Authorization parameters (only for authorization_code grant type)
44
+ { type: 'authorization', sendIn: 'headers', source: 'oauth2_additional_parameters_auth_req_headers' },
45
+ { type: 'authorization', sendIn: 'queryparams', source: 'oauth2_additional_parameters_auth_req_queryparams' },
46
+
47
+ // Token parameters (for all grant types)
48
+ { type: 'token', sendIn: 'headers', source: 'oauth2_additional_parameters_access_token_req_headers' },
49
+ { type: 'token', sendIn: 'queryparams', source: 'oauth2_additional_parameters_access_token_req_queryparams' },
50
+ { type: 'token', sendIn: 'body', source: 'oauth2_additional_parameters_access_token_req_bodyvalues' },
51
+
52
+ // Refresh parameters (for grant types that support refresh)
53
+ { type: 'refresh', sendIn: 'headers', source: 'oauth2_additional_parameters_refresh_token_req_headers' },
54
+ { type: 'refresh', sendIn: 'queryparams', source: 'oauth2_additional_parameters_refresh_token_req_queryparams' },
55
+ { type: 'refresh', sendIn: 'body', source: 'oauth2_additional_parameters_refresh_token_req_bodyvalues' },
56
+ ];
57
+
58
+ /**
59
+ * Maps source parameters to T_OAuth2AdditionalParam format
60
+ */
61
+ const mapParametersFromSource = (sourceParams: any[], sendIn: T_Oauth2ParameterSendInType): T_OAuth2AdditionalParam[] => {
62
+ if (!sourceParams?.length) {
63
+ return [];
64
+ }
65
+
66
+ return sourceParams.map(param => ({
67
+ ...param,
68
+ sendIn
69
+ }));
70
+ };
71
+
72
+ /**
73
+ * Checks if a parameter type should be included based on grant type
74
+ */
75
+ const shouldIncludeParameterType = (type: T_Oauth2ParameterType, grantType: string): boolean => {
76
+ // Authorization parameters are only valid for authorization_code grant type
77
+ if (type === 'authorization') {
78
+ return grantType === 'authorization_code' || grantType === 'implicit';
79
+ }
80
+
81
+ if (type === 'token' || type === 'refresh') {
82
+ return grantType !== 'implicit';
83
+ }
84
+
85
+ // Token and refresh parameters are valid for all grant types
86
+ return true;
87
+ };
88
+
89
+ /**
90
+ * Collects all parameters for a specific type (authorization, token, or refresh)
91
+ */
92
+ const collectParametersForType = (
93
+ json: T_BruJson,
94
+ type: T_Oauth2ParameterType,
95
+ grantType: string
96
+ ): T_OAuth2AdditionalParam[] => {
97
+ if (!shouldIncludeParameterType(type, grantType)) {
98
+ return [];
99
+ }
100
+
101
+ const relevantMappings = PARAMETER_MAPPINGS.filter(mapping => mapping.type === type);
102
+ const allParams: T_OAuth2AdditionalParam[] = [];
103
+
104
+ for (const mapping of relevantMappings) {
105
+ const sourceParams = json[mapping.source] as any[];
106
+ const mappedParams = mapParametersFromSource(sourceParams, mapping.sendIn);
107
+ allParams.push(...mappedParams);
108
+ }
109
+
110
+ return allParams;
111
+ };
112
+
113
+ /**
114
+ * This function extracts OAuth2 additional parameters from various sources in the bru json data and organizes
115
+ * them into a structured format based on their usage context (authorization, token, refresh).
116
+ *
117
+ * @param json - json object containing OAuth2 configuration and additional parameters
118
+ * @returns OAuth2 additional parameters
119
+ */
120
+ export const getOauth2AdditionalParameters = (json: T_BruJson): T_OAuth2AdditionalParameters => {
121
+ const grantType = json.auth.oauth2.grantType;
122
+ const additionalParameters: T_OAuth2AdditionalParameters = {};
123
+
124
+ try {
125
+ // Collect parameters for each type
126
+ const parameterTypes: T_Oauth2ParameterType[] = ['authorization', 'token', 'refresh'];
127
+
128
+ for (const type of parameterTypes) {
129
+ const params = collectParametersForType(json, type, grantType);
130
+ if (params.length > 0) {
131
+ additionalParameters[type] = params;
132
+ }
133
+ }
134
+ }
135
+ catch(error) {
136
+ console.error(error);
137
+ console.error("Error while getting the oauth2 additional parameters!");
138
+ }
139
+
140
+ return additionalParameters;
141
+ };
@@ -0,0 +1,77 @@
1
+ /**
2
+ * Parses a .bru file and extracts body content while redacting it from the main content
3
+ * @param {string} bruFileContent - The raw content of the .bru file
4
+ * @returns {Object} Object containing redacted file content and extracted body data
5
+ */
6
+ export const bruRequestParseAndRedactBodyData = (bruFileContent: string) => {
7
+ try {
8
+ // Define the patterns that indicate the start of different body types
9
+ const bodyTypePatterns = [
10
+ "body:json {",
11
+ "body:text {",
12
+ "body:xml {",
13
+ "body:sparql {",
14
+ "body:graphql {"
15
+ ];
16
+
17
+ // Normalize line endings to LF
18
+ bruFileContent = (bruFileContent || '').replace(/\r\n/g, '\n');
19
+
20
+ const EOL = `\n`;
21
+
22
+ /**
23
+ * Removes the leading 2-space indentation from each line of a string
24
+ * @param {string} indentedString - The string with leading spaces to remove
25
+ * @returns {string} The string with indentation removed
26
+ */
27
+ const removeLeadingIndentation = (indentedString: string) => {
28
+ if (!indentedString || !indentedString.length) {
29
+ return indentedString || '';
30
+ }
31
+
32
+ return indentedString
33
+ .split(EOL)
34
+ .map((line) => line.replace(/^ /, ''))
35
+ .join(EOL);
36
+ };
37
+
38
+ // Split the file content into blocks
39
+ let fileContentBlocks = bruFileContent.split(`${EOL}}${EOL}`);
40
+ fileContentBlocks = fileContentBlocks.filter(Boolean).map(_ => _.trim());
41
+
42
+ // Extract body blocks and their content
43
+ const extractedBodyBlocks = fileContentBlocks
44
+ .filter(block => bodyTypePatterns.some(pattern => block.startsWith(pattern)))
45
+ .reduce((bodyContentMap: Record<string, string>, bodyBlock) => {
46
+ // Extract the body type (json, text, xml, etc.) from the first line
47
+ const firstLine = bodyBlock.split(EOL)[0];
48
+ const bodyType = firstLine.split(`body:`)[1].split(/\s/)[0];
49
+
50
+ // Extract the body content (everything between the opening and closing braces)
51
+ const bodyContentLines = bodyBlock.split(EOL).slice(1);
52
+ const rawBodyContent = bodyContentLines.join(EOL);
53
+
54
+ // Remove indentation from the body content
55
+ const cleanBodyContent = removeLeadingIndentation(rawBodyContent);
56
+
57
+ bodyContentMap[bodyType] = cleanBodyContent;
58
+ return bodyContentMap;
59
+ }, {});
60
+
61
+ // Filter out body blocks to get the remaining file content
62
+ const fileContentWithoutBodyBlocks = fileContentBlocks.filter(block =>
63
+ !bodyTypePatterns.some(pattern => block.startsWith(pattern))
64
+ );
65
+
66
+ return {
67
+ bruFileStringWithRedactedBody: fileContentWithoutBodyBlocks.join(`${EOL}}${EOL}${EOL}`).concat(`${EOL}}${EOL}`),
68
+ extractedBodyContent: extractedBodyBlocks
69
+ };
70
+ } catch (error) {
71
+ console.error('Error parsing and redacting body data:', error);
72
+ return {
73
+ bruFileStringWithRedactedBody: bruFileContent,
74
+ extractedBodyContent: {}
75
+ };
76
+ }
77
+ };
package/src/index.ts CHANGED
@@ -15,6 +15,7 @@ import {
15
15
  ParsedCollection,
16
16
  ParsedEnvironment
17
17
  } from './types';
18
+ import { bruRequestParseAndRedactBodyData } from './formats/bru/utils/request-parse-and-redact-body-data';
18
19
 
19
20
  export const parseRequest = (content: string, options: ParseOptions = { format: 'bru' }): any => {
20
21
  if (options.format === 'bru') {
@@ -23,6 +24,13 @@ export const parseRequest = (content: string, options: ParseOptions = { format:
23
24
  throw new Error(`Unsupported format: ${options.format}`);
24
25
  };
25
26
 
27
+ export const parseRequestAndRedactBody = (content: string, options: ParseOptions = { format: 'bru' }): any => {
28
+ if (options.format === 'bru') {
29
+ return bruRequestParseAndRedactBodyData(content);
30
+ }
31
+ throw new Error(`Unsupported format: ${options.format}`);
32
+ };
33
+
26
34
  export const stringifyRequest = (requestObj: ParsedRequest, options: StringifyOptions = { format: 'bru' }): string => {
27
35
  if (options.format === 'bru') {
28
36
  return jsonRequestToBru(requestObj);