Skip to content

Commit 4ec6d92

Browse files
authored
Merge pull request #6 from JS00001/main
Add custom headers
2 parents b46bd3c + 93639da commit 4ec6d92

File tree

17 files changed

+454
-243
lines changed

17 files changed

+454
-243
lines changed

bridge/tauri.conf.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"$schema": "https://schema.tauri.app/config/2",
33
"productName": "HTTP Interceptor",
4-
"version": "0.1.7",
4+
"version": "0.1.8",
55
"identifier": "com.http-interceptor.js00001",
66
"build": {
77
"beforeDevCommand": "npm run dev",

interceptor/chrome/tab-listener.ts

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { GREEN } from '@shared/lib';
55
import { CDP, NetworkEvent } from '@shared/types';
66
import { requestStore } from '@shared/stores/network-event';
77
import SocketManager from '@interceptor/lib/socket-manager';
8-
import { rulesStore } from '@shared/stores/interceptor-rules';
8+
import { preferencesStore } from '@shared/stores/preferences';
99
import { getRequestParams, matchesInterceptorField } from '@shared/lib';
1010

1111
export default class TabListener extends SocketManager {
@@ -121,15 +121,35 @@ export default class TabListener extends SocketManager {
121121
return;
122122
}
123123

124+
// Calculate the custom headers that we want to add to the request
125+
const customHeaders = preferencesStore.getState().customHeaders;
126+
const enabledHeaders = customHeaders.filter((header) => {
127+
return header.enabled && header.key && header.value;
128+
});
129+
130+
const transformedHeaders = Object.fromEntries(
131+
enabledHeaders.map((header) => {
132+
return [header.key, header.value];
133+
})
134+
);
135+
124136
// Default requests from Network.requestWillBeSent don't intercept the body/post data, so we need
125-
// to add that data manually, since Fetch.requestPaused does contain it
137+
// to add that data manually, since Fetch.requestPaused does contain it. We also add our custom headers to every request here, as soon
138+
// as we pause it
126139
requestStore.getState().addOrUpdateRequest({
127140
requestId,
128141
tabId: this.id,
129-
request: params.request,
142+
request: {
143+
...params.request,
144+
headers: {
145+
...params.request.headers,
146+
...transformedHeaders,
147+
},
148+
},
130149
});
131150

132-
const rules = rulesStore.getState().rules;
151+
// Handle whether we intercept the request or not based on rules
152+
const rules = preferencesStore.getState().rules;
133153
const requestParams = getRequestParams(params.request);
134154

135155
const urlString = params.request.url;

shared/lib/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ export const getRequestParams = (request: Protocol.Network.Request) => {
4242

4343
if (boundary) {
4444
const formData = parseFormData(request.postData, boundary);
45-
reqParams.postDataType = 'form-data';
45+
reqParams.postDataType = Object.keys(formData).length > 0 ? 'form-data' : null;
4646
reqParams.postData = formData;
4747
}
4848
}

shared/stores/interceptor-rules.ts

Lines changed: 0 additions & 96 deletions
This file was deleted.

shared/stores/preferences.ts

Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
import { produce } from 'immer';
2+
import { create } from 'zustand';
3+
import { persist } from 'zustand/middleware';
4+
5+
import { CustomHeader, InterceptorRule, ThemeColor } from '@shared/types';
6+
7+
interface IPreferencesState {
8+
hasHydrated: boolean;
9+
theme: ThemeColor;
10+
rules: InterceptorRule[];
11+
customHeaders: CustomHeader[];
12+
}
13+
14+
interface IPreferencesStore extends IPreferencesState {
15+
// Custom header methods
16+
addHeader: () => void;
17+
removeHeader: (id: string) => void;
18+
updateHeader: (header: CustomHeader) => void;
19+
20+
// Rule methods
21+
addRule: () => void;
22+
removeRule: (id: string) => void;
23+
updateRule: (rule: InterceptorRule) => void;
24+
25+
// Other preferences/methods
26+
setTheme: (theme: IPreferencesState['theme']) => void;
27+
hydrate: () => void;
28+
}
29+
30+
const usePreferencesStore = create<IPreferencesStore>()(
31+
persist(
32+
(set) => {
33+
const initialState: IPreferencesState = {
34+
rules: [],
35+
customHeaders: [],
36+
theme: 'indigo',
37+
hasHydrated: false,
38+
};
39+
40+
const setTheme = (theme: IPreferencesState['theme']) => {
41+
set(
42+
produce((draft) => {
43+
draft.theme = theme;
44+
})
45+
);
46+
};
47+
48+
/**
49+
* Add a new custom header This adds a new row to the table and wont add the header
50+
* until a key and value are provided
51+
*/
52+
const addHeader = () => {
53+
set((state) =>
54+
produce(state, (draft) => {
55+
draft.customHeaders.push({
56+
id: crypto.randomUUID(),
57+
key: '',
58+
value: '',
59+
enabled: true,
60+
});
61+
})
62+
);
63+
};
64+
65+
/**
66+
* Update an existing header to new values. Matches based
67+
* on ID
68+
*/
69+
const updateHeader = (header: CustomHeader) => {
70+
set((state) => ({
71+
customHeaders: state.customHeaders.map((h) => (h.id === header.id ? header : h)),
72+
}));
73+
};
74+
75+
/**
76+
* Remove a rule based on its ID. Requests will no longer be
77+
* intercepted for this rule
78+
*/
79+
const removeHeader = (id: string) => {
80+
set((state) => ({
81+
customHeaders: state.customHeaders.filter((h) => h.id !== id),
82+
}));
83+
};
84+
85+
/**
86+
* Add a new interceptor rule. This adds a new row to the table and wont actually
87+
* intercept anything until the value is not empty
88+
*/
89+
const addRule = () => {
90+
set((state) =>
91+
produce(state, (draft) => {
92+
draft.rules.push({
93+
id: crypto.randomUUID(),
94+
field: 'url',
95+
operator: 'equals',
96+
value: '',
97+
enabled: true,
98+
});
99+
})
100+
);
101+
};
102+
103+
/**
104+
* Update an existing interceptor rule to new values. Matches based
105+
* on ID
106+
*/
107+
const updateRule = (rule: InterceptorRule) => {
108+
set((state) => ({
109+
rules: state.rules.map((r) => (r.id === rule.id ? rule : r)),
110+
}));
111+
};
112+
113+
/**
114+
* Remove a rule based on its ID. Requests will no longer be
115+
* intercepted for this rule
116+
*/
117+
const removeRule = (id: string) => {
118+
set((state) => ({ rules: state.rules.filter((r) => r.id !== id) }));
119+
};
120+
121+
/**
122+
* Mark the store as hydrated from persisted data
123+
*/
124+
const hydrate = () => {
125+
set((state) => ({ ...state, hasHydrated: true }));
126+
};
127+
128+
return {
129+
...initialState,
130+
setTheme,
131+
addHeader,
132+
removeHeader,
133+
updateHeader,
134+
addRule,
135+
removeRule,
136+
updateRule,
137+
hydrate,
138+
};
139+
},
140+
{
141+
name: 'preferences-store',
142+
onRehydrateStorage: () => {
143+
return (state, error) => {
144+
if (error || !state) {
145+
return state;
146+
}
147+
148+
return state.hydrate();
149+
};
150+
},
151+
}
152+
)
153+
);
154+
155+
export default usePreferencesStore;
156+
157+
// For static initializations, so the var name looks cleaner
158+
export const preferencesStore = usePreferencesStore;

shared/types.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,17 @@ export interface NetworkEvent {
2929
response?: Protocol.Network.Response;
3030
}
3131

32+
export type ThemeColor =
33+
| 'red'
34+
| 'blue'
35+
| 'indigo'
36+
| 'emerald'
37+
| 'fuchsia'
38+
| 'orange'
39+
| 'green'
40+
| 'purple'
41+
| 'teal';
42+
3243
export type InterceptorRuleField = 'url' | 'method' | 'params' | 'paramName';
3344

3445
export type InterceptorRuleOperator = 'equals' | 'contains' | 'notEquals' | 'notContains';
@@ -41,6 +52,13 @@ export interface InterceptorRule {
4152
enabled: boolean;
4253
}
4354

55+
export interface CustomHeader {
56+
id: string;
57+
key: string;
58+
value: string;
59+
enabled: boolean;
60+
}
61+
4462
/**
4563
* Response types for tauri commands
4664
*/

ui/components/modals/Configure.tsx

Lines changed: 0 additions & 43 deletions
This file was deleted.

0 commit comments

Comments
 (0)