diff --git a/admin/.eslintrc.json b/admin/.eslintrc.json
index a901afe..c1f671b 100644
--- a/admin/.eslintrc.json
+++ b/admin/.eslintrc.json
@@ -17,7 +17,12 @@
"prettier/prettier": ["error"],
"@next/next/no-css-tags": "off",
"no-unused-vars": "off",
- "@typescript-eslint/no-unused-vars": "error",
+ "@typescript-eslint/no-unused-vars": [
+ "error",
+ {
+ "ignoreRestSiblings": true
+ }
+ ],
"import/default": "off",
diff --git a/admin/src/features/Layout.tsx b/admin/src/features/Layout.tsx
index 9a76d5a..6495d0f 100644
--- a/admin/src/features/Layout.tsx
+++ b/admin/src/features/Layout.tsx
@@ -41,6 +41,7 @@ export enum Page {
ProxyLogs,
Sender,
Scope,
+ Settings,
}
const drawerWidth = 240;
diff --git a/admin/src/features/intercept/components/EditRequest.tsx b/admin/src/features/intercept/components/EditRequest.tsx
index a15086e..e939531 100644
--- a/admin/src/features/intercept/components/EditRequest.tsx
+++ b/admin/src/features/intercept/components/EditRequest.tsx
@@ -1,11 +1,13 @@
import CancelIcon from "@mui/icons-material/Cancel";
import SendIcon from "@mui/icons-material/Send";
-import { Alert, Box, Button, CircularProgress, Typography } from "@mui/material";
+import SettingsIcon from "@mui/icons-material/Settings";
+import { Alert, Box, Button, CircularProgress, IconButton, Tooltip, Typography } from "@mui/material";
import { useRouter } from "next/router";
import React, { useEffect, useState } from "react";
import { useInterceptedRequests } from "lib/InterceptedRequestsContext";
import { KeyValuePair, sortKeyValuePairs } from "lib/components/KeyValuePair";
+import Link from "lib/components/Link";
import RequestTabs from "lib/components/RequestTabs";
import Response from "lib/components/Response";
import SplitPane from "lib/components/SplitPane";
@@ -201,6 +203,11 @@ function EditRequest(): JSX.Element {
>
Cancel
+
+
+
+
+
{modifyResult.error && (
diff --git a/admin/src/features/projects/components/ProjectList.tsx b/admin/src/features/projects/components/ProjectList.tsx
index 3ad2dd0..7e156c5 100644
--- a/admin/src/features/projects/components/ProjectList.tsx
+++ b/admin/src/features/projects/components/ProjectList.tsx
@@ -2,6 +2,7 @@ import CloseIcon from "@mui/icons-material/Close";
import DeleteIcon from "@mui/icons-material/Delete";
import DescriptionIcon from "@mui/icons-material/Description";
import LaunchIcon from "@mui/icons-material/Launch";
+import SettingsIcon from "@mui/icons-material/Settings";
import { Alert } from "@mui/lab";
import {
Avatar,
@@ -29,6 +30,7 @@ import React, { useState } from "react";
import useOpenProjectMutation from "../hooks/useOpenProjectMutation";
+import Link, { NextLinkComposed } from "lib/components/Link";
import {
ProjectsQuery,
useCloseProjectMutation,
@@ -179,6 +181,11 @@ function ProjectList(): JSX.Element {
{project.name} {project.isActive && (Active)}
+
+
+
+
+
{project.isActive && (
closeProject()}>
diff --git a/admin/src/features/projects/graphql/activeProject.graphql b/admin/src/features/projects/graphql/activeProject.graphql
new file mode 100644
index 0000000..7350999
--- /dev/null
+++ b/admin/src/features/projects/graphql/activeProject.graphql
@@ -0,0 +1,12 @@
+query ActiveProject {
+ activeProject {
+ id
+ name
+ isActive
+ settings {
+ intercept {
+ enabled
+ }
+ }
+ }
+}
diff --git a/admin/src/features/reqlog/components/Actions.tsx b/admin/src/features/reqlog/components/Actions.tsx
index 0e755b2..bc16d7b 100644
--- a/admin/src/features/reqlog/components/Actions.tsx
+++ b/admin/src/features/reqlog/components/Actions.tsx
@@ -4,11 +4,13 @@ import { Alert } from "@mui/lab";
import { Badge, Button, IconButton, Tooltip } from "@mui/material";
import Link from "next/link";
+import { useActiveProject } from "lib/ActiveProjectContext";
import { useInterceptedRequests } from "lib/InterceptedRequestsContext";
import { ConfirmationDialog, useConfirmationDialog } from "lib/components/ConfirmationDialog";
import { HttpRequestLogsDocument, useClearHttpRequestLogMutation } from "lib/graphql/generated";
function Actions(): JSX.Element {
+ const activeProject = useActiveProject();
const interceptedRequests = useInterceptedRequests();
const [clearHTTPRequestLog, clearLogsResult] = useClearHttpRequestLogMutation({
refetchQueries: [{ query: HttpRequestLogsDocument }],
@@ -27,23 +29,25 @@ function Actions(): JSX.Element {
{clearLogsResult.error && Failed to clear HTTP logs: {clearLogsResult.error}}
-
-
-
+ {activeProject?.settings.intercept.enabled && (
+
+
+
+ )}
diff --git a/admin/src/features/settings/components/Settings.tsx b/admin/src/features/settings/components/Settings.tsx
new file mode 100644
index 0000000..f9210e5
--- /dev/null
+++ b/admin/src/features/settings/components/Settings.tsx
@@ -0,0 +1,95 @@
+import { useApolloClient } from "@apollo/client";
+import { TabContext, TabPanel } from "@mui/lab";
+import TabList from "@mui/lab/TabList";
+import { Box, FormControl, FormControlLabel, FormHelperText, Switch, Tab, Typography } from "@mui/material";
+import { SwitchBaseProps } from "@mui/material/internal/SwitchBase";
+import { useState } from "react";
+
+import { useActiveProject } from "lib/ActiveProjectContext";
+import Link from "lib/components/Link";
+import { ActiveProjectDocument, useUpdateInterceptSettingsMutation } from "lib/graphql/generated";
+
+enum TabValue {
+ Intercept = "intercept",
+}
+
+export default function Settings(): JSX.Element {
+ const client = useApolloClient();
+ const activeProject = useActiveProject();
+ const [updateInterceptSettings, updateIntercepSettingsResult] = useUpdateInterceptSettingsMutation();
+
+ const handleInterceptEnabled: SwitchBaseProps["onChange"] = (_, checked) => {
+ updateInterceptSettings({
+ variables: {
+ input: {
+ enabled: checked,
+ },
+ },
+ onCompleted(data) {
+ client.cache.updateQuery({ query: ActiveProjectDocument }, (cachedData) => ({
+ activeProject: {
+ ...cachedData.activeProject,
+ settings: {
+ intercept: data.updateInterceptSettings,
+ },
+ },
+ }));
+ },
+ });
+ };
+
+ const [tabValue, setTabValue] = useState(TabValue.Intercept);
+
+ const tabSx = {
+ textTransform: "none",
+ };
+
+ return (
+
+
+ Settings
+
+
+ Settings allow you to tweak the behaviour of Hetty’s features.
+
+
+ Project settings
+
+ {!activeProject && (
+
+ There is no project active. To configure project settings, first open a project.
+
+ )}
+ {activeProject && (
+ <>
+
+ setTabValue(value)} sx={{ borderBottom: 1, borderColor: "divider" }}>
+
+
+
+
+
+
+ }
+ label="Enable proxy interception"
+ labelPlacement="start"
+ sx={{ display: "inline-block", m: 0 }}
+ />
+
+ When enabled, incoming HTTP requests to the proxy are stalled for{" "}
+ manual review.
+
+
+
+
+ >
+ )}
+
+ );
+}
diff --git a/admin/src/features/settings/graphql/updateInterceptSettings.graphql b/admin/src/features/settings/graphql/updateInterceptSettings.graphql
new file mode 100644
index 0000000..0896ade
--- /dev/null
+++ b/admin/src/features/settings/graphql/updateInterceptSettings.graphql
@@ -0,0 +1,5 @@
+mutation UpdateInterceptSettings($input: UpdateInterceptSettingsInput!) {
+ updateInterceptSettings(input: $input) {
+ enabled
+ }
+}
diff --git a/admin/src/lib/ActiveProjectContext.tsx b/admin/src/lib/ActiveProjectContext.tsx
index 3bc35bc..a28eca6 100644
--- a/admin/src/lib/ActiveProjectContext.tsx
+++ b/admin/src/lib/ActiveProjectContext.tsx
@@ -1,6 +1,6 @@
import React, { createContext, useContext } from "react";
-import { Project, useProjectsQuery } from "./graphql/generated";
+import { Project, useActiveProjectQuery } from "./graphql/generated";
const ActiveProjectContext = createContext(null);
@@ -9,8 +9,8 @@ interface Props {
}
export function ActiveProjectProvider({ children }: Props): JSX.Element {
- const { data } = useProjectsQuery();
- const project = data?.projects.find((project) => project.isActive) || null;
+ const { data } = useActiveProjectQuery();
+ const project = data?.activeProject || null;
return {children};
}
diff --git a/admin/src/lib/components/Link.tsx b/admin/src/lib/components/Link.tsx
new file mode 100644
index 0000000..a9d8a51
--- /dev/null
+++ b/admin/src/lib/components/Link.tsx
@@ -0,0 +1,94 @@
+import MuiLink, { LinkProps as MuiLinkProps } from "@mui/material/Link";
+import { styled } from "@mui/material/styles";
+import clsx from "clsx";
+import NextLink, { LinkProps as NextLinkProps } from "next/link";
+import { useRouter } from "next/router";
+import * as React from "react";
+
+// Add support for the sx prop for consistency with the other branches.
+const Anchor = styled("a")({});
+
+interface NextLinkComposedProps
+ extends Omit, "href">,
+ Omit {
+ to: NextLinkProps["href"];
+ linkAs?: NextLinkProps["as"];
+}
+
+export const NextLinkComposed = React.forwardRef(function NextLinkComposed(
+ props,
+ ref
+) {
+ const { to, linkAs, replace, scroll, shallow, prefetch, locale, ...other } = props;
+
+ return (
+
+
+
+ );
+});
+
+export type LinkProps = {
+ activeClassName?: string;
+ as?: NextLinkProps["as"];
+ href: NextLinkProps["href"];
+ linkAs?: NextLinkProps["as"]; // Useful when the as prop is shallow by styled().
+ noLinkStyle?: boolean;
+} & Omit &
+ Omit;
+
+// A styled version of the Next.js Link component:
+// https://nextjs.org/docs/api-reference/next/link
+const Link = React.forwardRef(function Link(props, ref) {
+ const {
+ activeClassName = "active",
+ as,
+ className: classNameProps,
+ href,
+ linkAs: linkAsProp,
+ locale,
+ noLinkStyle,
+ prefetch,
+ replace,
+ role, // Link don't have roles.
+ scroll,
+ shallow,
+ ...other
+ } = props;
+
+ const router = useRouter();
+ const pathname = typeof href === "string" ? href : href.pathname;
+ const className = clsx(classNameProps, {
+ [activeClassName]: router.pathname === pathname && activeClassName,
+ });
+
+ const isExternal = typeof href === "string" && (href.indexOf("http") === 0 || href.indexOf("mailto:") === 0);
+
+ if (isExternal) {
+ if (noLinkStyle) {
+ return ;
+ }
+
+ return ;
+ }
+
+ const linkAs = linkAsProp || as;
+ const nextjsProps = { to: href, linkAs, replace, scroll, shallow, prefetch, locale };
+
+ if (noLinkStyle) {
+ return ;
+ }
+
+ return ;
+});
+
+export default Link;
diff --git a/admin/src/lib/graphql/generated.tsx b/admin/src/lib/graphql/generated.tsx
index 79d9461..29865f4 100644
--- a/admin/src/lib/graphql/generated.tsx
+++ b/admin/src/lib/graphql/generated.tsx
@@ -116,6 +116,11 @@ export type HttpResponseLog = {
statusReason: Scalars['String'];
};
+export type InterceptSettings = {
+ __typename?: 'InterceptSettings';
+ enabled: Scalars['Boolean'];
+};
+
export type ModifyRequestInput = {
body?: InputMaybe;
headers?: InputMaybe>;
@@ -146,6 +151,7 @@ export type Mutation = {
setHttpRequestLogFilter?: Maybe;
setScope: Array;
setSenderRequestFilter?: Maybe;
+ updateInterceptSettings: InterceptSettings;
};
@@ -203,11 +209,22 @@ export type MutationSetSenderRequestFilterArgs = {
filter?: InputMaybe;
};
+
+export type MutationUpdateInterceptSettingsArgs = {
+ input: UpdateInterceptSettingsInput;
+};
+
export type Project = {
__typename?: 'Project';
id: Scalars['ID'];
isActive: Scalars['Boolean'];
name: Scalars['String'];
+ settings: ProjectSettings;
+};
+
+export type ProjectSettings = {
+ __typename?: 'ProjectSettings';
+ intercept: InterceptSettings;
};
export type Query = {
@@ -296,6 +313,10 @@ export type SenderRequestInput = {
url: Scalars['URL'];
};
+export type UpdateInterceptSettingsInput = {
+ enabled: Scalars['Boolean'];
+};
+
export type CancelRequestMutationVariables = Exact<{
id: Scalars['ID'];
}>;
@@ -317,6 +338,11 @@ export type ModifyRequestMutationVariables = Exact<{
export type ModifyRequestMutation = { __typename?: 'Mutation', modifyRequest: { __typename?: 'ModifyRequestResult', success: boolean } };
+export type ActiveProjectQueryVariables = Exact<{ [key: string]: never; }>;
+
+
+export type ActiveProjectQuery = { __typename?: 'Query', activeProject?: { __typename?: 'Project', id: string, name: string, isActive: boolean, settings: { __typename?: 'ProjectSettings', intercept: { __typename?: 'InterceptSettings', enabled: boolean } } } | null };
+
export type CloseProjectMutationVariables = Exact<{ [key: string]: never; }>;
@@ -422,6 +448,13 @@ export type GetSenderRequestsQueryVariables = Exact<{ [key: string]: never; }>;
export type GetSenderRequestsQuery = { __typename?: 'Query', senderRequests: Array<{ __typename?: 'SenderRequest', id: string, url: any, method: HttpMethod, response?: { __typename?: 'HttpResponseLog', id: string, statusCode: number, statusReason: string } | null }> };
+export type UpdateInterceptSettingsMutationVariables = Exact<{
+ input: UpdateInterceptSettingsInput;
+}>;
+
+
+export type UpdateInterceptSettingsMutation = { __typename?: 'Mutation', updateInterceptSettings: { __typename?: 'InterceptSettings', enabled: boolean } };
+
export type GetInterceptedRequestsQueryVariables = Exact<{ [key: string]: never; }>;
@@ -537,6 +570,47 @@ export function useModifyRequestMutation(baseOptions?: Apollo.MutationHookOption
export type ModifyRequestMutationHookResult = ReturnType;
export type ModifyRequestMutationResult = Apollo.MutationResult;
export type ModifyRequestMutationOptions = Apollo.BaseMutationOptions;
+export const ActiveProjectDocument = gql`
+ query ActiveProject {
+ activeProject {
+ id
+ name
+ isActive
+ settings {
+ intercept {
+ enabled
+ }
+ }
+ }
+}
+ `;
+
+/**
+ * __useActiveProjectQuery__
+ *
+ * To run a query within a React component, call `useActiveProjectQuery` and pass it any options that fit your needs.
+ * When your component renders, `useActiveProjectQuery` returns an object from Apollo Client that contains loading, error, and data properties
+ * you can use to render your UI.
+ *
+ * @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
+ *
+ * @example
+ * const { data, loading, error } = useActiveProjectQuery({
+ * variables: {
+ * },
+ * });
+ */
+export function useActiveProjectQuery(baseOptions?: Apollo.QueryHookOptions) {
+ const options = {...defaultOptions, ...baseOptions}
+ return Apollo.useQuery(ActiveProjectDocument, options);
+ }
+export function useActiveProjectLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions) {
+ const options = {...defaultOptions, ...baseOptions}
+ return Apollo.useLazyQuery(ActiveProjectDocument, options);
+ }
+export type ActiveProjectQueryHookResult = ReturnType;
+export type ActiveProjectLazyQueryHookResult = ReturnType;
+export type ActiveProjectQueryResult = Apollo.QueryResult;
export const CloseProjectDocument = gql`
mutation CloseProject {
closeProject {
@@ -1166,6 +1240,39 @@ export function useGetSenderRequestsLazyQuery(baseOptions?: Apollo.LazyQueryHook
export type GetSenderRequestsQueryHookResult = ReturnType;
export type GetSenderRequestsLazyQueryHookResult = ReturnType;
export type GetSenderRequestsQueryResult = Apollo.QueryResult;
+export const UpdateInterceptSettingsDocument = gql`
+ mutation UpdateInterceptSettings($input: UpdateInterceptSettingsInput!) {
+ updateInterceptSettings(input: $input) {
+ enabled
+ }
+}
+ `;
+export type UpdateInterceptSettingsMutationFn = Apollo.MutationFunction;
+
+/**
+ * __useUpdateInterceptSettingsMutation__
+ *
+ * To run a mutation, you first call `useUpdateInterceptSettingsMutation` within a React component and pass it any options that fit your needs.
+ * When your component renders, `useUpdateInterceptSettingsMutation` returns a tuple that includes:
+ * - A mutate function that you can call at any time to execute the mutation
+ * - An object with fields that represent the current status of the mutation's execution
+ *
+ * @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2;
+ *
+ * @example
+ * const [updateInterceptSettingsMutation, { data, loading, error }] = useUpdateInterceptSettingsMutation({
+ * variables: {
+ * input: // value for 'input'
+ * },
+ * });
+ */
+export function useUpdateInterceptSettingsMutation(baseOptions?: Apollo.MutationHookOptions) {
+ const options = {...defaultOptions, ...baseOptions}
+ return Apollo.useMutation(UpdateInterceptSettingsDocument, options);
+ }
+export type UpdateInterceptSettingsMutationHookResult = ReturnType;
+export type UpdateInterceptSettingsMutationResult = Apollo.MutationResult;
+export type UpdateInterceptSettingsMutationOptions = Apollo.BaseMutationOptions;
export const GetInterceptedRequestsDocument = gql`
query GetInterceptedRequests {
interceptedRequests {
diff --git a/admin/src/pages/settings/index.tsx b/admin/src/pages/settings/index.tsx
new file mode 100644
index 0000000..64150dd
--- /dev/null
+++ b/admin/src/pages/settings/index.tsx
@@ -0,0 +1,12 @@
+import { Layout, Page } from "features/Layout";
+import Settings from "features/settings/components/Settings";
+
+function Index(): JSX.Element {
+ return (
+
+
+
+ );
+}
+
+export default Index;
diff --git a/pkg/api/generated.go b/pkg/api/generated.go
index 5ad3515..bb693df 100644
--- a/pkg/api/generated.go
+++ b/pkg/api/generated.go
@@ -104,6 +104,10 @@ type ComplexityRoot struct {
StatusReason func(childComplexity int) int
}
+ InterceptSettings struct {
+ Enabled func(childComplexity int) int
+ }
+
ModifyRequestResult struct {
Success func(childComplexity int) int
}
@@ -123,12 +127,18 @@ type ComplexityRoot struct {
SetHTTPRequestLogFilter func(childComplexity int, filter *HTTPRequestLogFilterInput) int
SetScope func(childComplexity int, scope []ScopeRuleInput) int
SetSenderRequestFilter func(childComplexity int, filter *SenderRequestFilterInput) int
+ UpdateInterceptSettings func(childComplexity int, input UpdateInterceptSettingsInput) int
}
Project struct {
ID func(childComplexity int) int
IsActive func(childComplexity int) int
Name func(childComplexity int) int
+ Settings func(childComplexity int) int
+ }
+
+ ProjectSettings struct {
+ Intercept func(childComplexity int) int
}
Query struct {
@@ -188,6 +198,7 @@ type MutationResolver interface {
DeleteSenderRequests(ctx context.Context) (*DeleteSenderRequestsResult, error)
ModifyRequest(ctx context.Context, request ModifyRequestInput) (*ModifyRequestResult, error)
CancelRequest(ctx context.Context, id ulid.ULID) (*CancelRequestResult, error)
+ UpdateInterceptSettings(ctx context.Context, input UpdateInterceptSettingsInput) (*InterceptSettings, error)
}
type QueryResolver interface {
HTTPRequestLog(ctx context.Context, id ulid.ULID) (*HTTPRequestLog, error)
@@ -420,6 +431,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
return e.complexity.HTTPResponseLog.StatusReason(childComplexity), true
+ case "InterceptSettings.enabled":
+ if e.complexity.InterceptSettings.Enabled == nil {
+ break
+ }
+
+ return e.complexity.InterceptSettings.Enabled(childComplexity), true
+
case "ModifyRequestResult.success":
if e.complexity.ModifyRequestResult.Success == nil {
break
@@ -580,6 +598,18 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
return e.complexity.Mutation.SetSenderRequestFilter(childComplexity, args["filter"].(*SenderRequestFilterInput)), true
+ case "Mutation.updateInterceptSettings":
+ if e.complexity.Mutation.UpdateInterceptSettings == nil {
+ break
+ }
+
+ args, err := ec.field_Mutation_updateInterceptSettings_args(context.TODO(), rawArgs)
+ if err != nil {
+ return 0, false
+ }
+
+ return e.complexity.Mutation.UpdateInterceptSettings(childComplexity, args["input"].(UpdateInterceptSettingsInput)), true
+
case "Project.id":
if e.complexity.Project.ID == nil {
break
@@ -601,6 +631,20 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
return e.complexity.Project.Name(childComplexity), true
+ case "Project.settings":
+ if e.complexity.Project.Settings == nil {
+ break
+ }
+
+ return e.complexity.Project.Settings(childComplexity), true
+
+ case "ProjectSettings.intercept":
+ if e.complexity.ProjectSettings.Intercept == nil {
+ break
+ }
+
+ return e.complexity.ProjectSettings.Intercept(childComplexity), true
+
case "Query.activeProject":
if e.complexity.Query.ActiveProject == nil {
break
@@ -894,6 +938,11 @@ type Project {
id: ID!
name: String!
isActive: Boolean!
+ settings: ProjectSettings!
+}
+
+type ProjectSettings {
+ intercept: InterceptSettings!
}
type ScopeRule {
@@ -1006,6 +1055,14 @@ type CancelRequestResult {
success: Boolean!
}
+input UpdateInterceptSettingsInput {
+ enabled: Boolean!
+}
+
+type InterceptSettings {
+ enabled: Boolean!
+}
+
type Query {
httpRequestLog(id: ID!): HttpRequestLog
httpRequestLogs: [HttpRequestLog!]!
@@ -1036,6 +1093,9 @@ type Mutation {
deleteSenderRequests: DeleteSenderRequestsResult!
modifyRequest(request: ModifyRequestInput!): ModifyRequestResult!
cancelRequest(id: ID!): CancelRequestResult!
+ updateInterceptSettings(
+ input: UpdateInterceptSettingsInput!
+ ): InterceptSettings!
}
enum HttpMethod {
@@ -1232,6 +1292,21 @@ func (ec *executionContext) field_Mutation_setSenderRequestFilter_args(ctx conte
return args, nil
}
+func (ec *executionContext) field_Mutation_updateInterceptSettings_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {
+ var err error
+ args := map[string]interface{}{}
+ var arg0 UpdateInterceptSettingsInput
+ if tmp, ok := rawArgs["input"]; ok {
+ ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("input"))
+ arg0, err = ec.unmarshalNUpdateInterceptSettingsInput2githubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐUpdateInterceptSettingsInput(ctx, tmp)
+ if err != nil {
+ return nil, err
+ }
+ }
+ args["input"] = arg0
+ return args, nil
+}
+
func (ec *executionContext) field_Query___type_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {
var err error
args := map[string]interface{}{}
@@ -2330,6 +2405,41 @@ func (ec *executionContext) _HttpResponseLog_headers(ctx context.Context, field
return ec.marshalNHttpHeader2ᚕgithubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐHTTPHeaderᚄ(ctx, field.Selections, res)
}
+func (ec *executionContext) _InterceptSettings_enabled(ctx context.Context, field graphql.CollectedField, obj *InterceptSettings) (ret graphql.Marshaler) {
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ fc := &graphql.FieldContext{
+ Object: "InterceptSettings",
+ Field: field,
+ Args: nil,
+ IsMethod: false,
+ IsResolver: false,
+ }
+
+ ctx = graphql.WithFieldContext(ctx, fc)
+ resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+ ctx = rctx // use context from middleware stack in children
+ return obj.Enabled, nil
+ })
+ if err != nil {
+ ec.Error(ctx, err)
+ return graphql.Null
+ }
+ if resTmp == nil {
+ if !graphql.HasFieldError(ctx, fc) {
+ ec.Errorf(ctx, "must not be null")
+ }
+ return graphql.Null
+ }
+ res := resTmp.(bool)
+ fc.Result = res
+ return ec.marshalNBoolean2bool(ctx, field.Selections, res)
+}
+
func (ec *executionContext) _ModifyRequestResult_success(ctx context.Context, field graphql.CollectedField, obj *ModifyRequestResult) (ret graphql.Marshaler) {
defer func() {
if r := recover(); r != nil {
@@ -2920,6 +3030,48 @@ func (ec *executionContext) _Mutation_cancelRequest(ctx context.Context, field g
return ec.marshalNCancelRequestResult2ᚖgithubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐCancelRequestResult(ctx, field.Selections, res)
}
+func (ec *executionContext) _Mutation_updateInterceptSettings(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ fc := &graphql.FieldContext{
+ Object: "Mutation",
+ Field: field,
+ Args: nil,
+ IsMethod: true,
+ IsResolver: true,
+ }
+
+ ctx = graphql.WithFieldContext(ctx, fc)
+ rawArgs := field.ArgumentMap(ec.Variables)
+ args, err := ec.field_Mutation_updateInterceptSettings_args(ctx, rawArgs)
+ if err != nil {
+ ec.Error(ctx, err)
+ return graphql.Null
+ }
+ fc.Args = args
+ resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+ ctx = rctx // use context from middleware stack in children
+ return ec.resolvers.Mutation().UpdateInterceptSettings(rctx, args["input"].(UpdateInterceptSettingsInput))
+ })
+ if err != nil {
+ ec.Error(ctx, err)
+ return graphql.Null
+ }
+ if resTmp == nil {
+ if !graphql.HasFieldError(ctx, fc) {
+ ec.Errorf(ctx, "must not be null")
+ }
+ return graphql.Null
+ }
+ res := resTmp.(*InterceptSettings)
+ fc.Result = res
+ return ec.marshalNInterceptSettings2ᚖgithubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐInterceptSettings(ctx, field.Selections, res)
+}
+
func (ec *executionContext) _Project_id(ctx context.Context, field graphql.CollectedField, obj *Project) (ret graphql.Marshaler) {
defer func() {
if r := recover(); r != nil {
@@ -3025,6 +3177,76 @@ func (ec *executionContext) _Project_isActive(ctx context.Context, field graphql
return ec.marshalNBoolean2bool(ctx, field.Selections, res)
}
+func (ec *executionContext) _Project_settings(ctx context.Context, field graphql.CollectedField, obj *Project) (ret graphql.Marshaler) {
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ fc := &graphql.FieldContext{
+ Object: "Project",
+ Field: field,
+ Args: nil,
+ IsMethod: false,
+ IsResolver: false,
+ }
+
+ ctx = graphql.WithFieldContext(ctx, fc)
+ resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+ ctx = rctx // use context from middleware stack in children
+ return obj.Settings, nil
+ })
+ if err != nil {
+ ec.Error(ctx, err)
+ return graphql.Null
+ }
+ if resTmp == nil {
+ if !graphql.HasFieldError(ctx, fc) {
+ ec.Errorf(ctx, "must not be null")
+ }
+ return graphql.Null
+ }
+ res := resTmp.(*ProjectSettings)
+ fc.Result = res
+ return ec.marshalNProjectSettings2ᚖgithubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐProjectSettings(ctx, field.Selections, res)
+}
+
+func (ec *executionContext) _ProjectSettings_intercept(ctx context.Context, field graphql.CollectedField, obj *ProjectSettings) (ret graphql.Marshaler) {
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ fc := &graphql.FieldContext{
+ Object: "ProjectSettings",
+ Field: field,
+ Args: nil,
+ IsMethod: false,
+ IsResolver: false,
+ }
+
+ ctx = graphql.WithFieldContext(ctx, fc)
+ resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+ ctx = rctx // use context from middleware stack in children
+ return obj.Intercept, nil
+ })
+ if err != nil {
+ ec.Error(ctx, err)
+ return graphql.Null
+ }
+ if resTmp == nil {
+ if !graphql.HasFieldError(ctx, fc) {
+ ec.Errorf(ctx, "must not be null")
+ }
+ return graphql.Null
+ }
+ res := resTmp.(*InterceptSettings)
+ fc.Result = res
+ return ec.marshalNInterceptSettings2ᚖgithubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐInterceptSettings(ctx, field.Selections, res)
+}
+
func (ec *executionContext) _Query_httpRequestLog(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
defer func() {
if r := recover(); r != nil {
@@ -5393,6 +5615,29 @@ func (ec *executionContext) unmarshalInputSenderRequestInput(ctx context.Context
return it, nil
}
+func (ec *executionContext) unmarshalInputUpdateInterceptSettingsInput(ctx context.Context, obj interface{}) (UpdateInterceptSettingsInput, error) {
+ var it UpdateInterceptSettingsInput
+ asMap := map[string]interface{}{}
+ for k, v := range obj.(map[string]interface{}) {
+ asMap[k] = v
+ }
+
+ for k, v := range asMap {
+ switch k {
+ case "enabled":
+ var err error
+
+ ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("enabled"))
+ it.Enabled, err = ec.unmarshalNBoolean2bool(ctx, v)
+ if err != nil {
+ return it, err
+ }
+ }
+ }
+
+ return it, nil
+}
+
// endregion **************************** input.gotpl *****************************
// region ************************** interface.gotpl ***************************
@@ -5751,6 +5996,33 @@ func (ec *executionContext) _HttpResponseLog(ctx context.Context, sel ast.Select
return out
}
+var interceptSettingsImplementors = []string{"InterceptSettings"}
+
+func (ec *executionContext) _InterceptSettings(ctx context.Context, sel ast.SelectionSet, obj *InterceptSettings) graphql.Marshaler {
+ fields := graphql.CollectFields(ec.OperationContext, sel, interceptSettingsImplementors)
+
+ out := graphql.NewFieldSet(fields)
+ var invalids uint32
+ for i, field := range fields {
+ switch field.Name {
+ case "__typename":
+ out.Values[i] = graphql.MarshalString("InterceptSettings")
+ case "enabled":
+ out.Values[i] = ec._InterceptSettings_enabled(ctx, field, obj)
+ if out.Values[i] == graphql.Null {
+ invalids++
+ }
+ default:
+ panic("unknown field " + strconv.Quote(field.Name))
+ }
+ }
+ out.Dispatch()
+ if invalids > 0 {
+ return graphql.Null
+ }
+ return out
+}
+
var modifyRequestResultImplementors = []string{"ModifyRequestResult"}
func (ec *executionContext) _ModifyRequestResult(ctx context.Context, sel ast.SelectionSet, obj *ModifyRequestResult) graphql.Marshaler {
@@ -5851,6 +6123,11 @@ func (ec *executionContext) _Mutation(ctx context.Context, sel ast.SelectionSet)
if out.Values[i] == graphql.Null {
invalids++
}
+ case "updateInterceptSettings":
+ out.Values[i] = ec._Mutation_updateInterceptSettings(ctx, field)
+ if out.Values[i] == graphql.Null {
+ invalids++
+ }
default:
panic("unknown field " + strconv.Quote(field.Name))
}
@@ -5888,6 +6165,38 @@ func (ec *executionContext) _Project(ctx context.Context, sel ast.SelectionSet,
if out.Values[i] == graphql.Null {
invalids++
}
+ case "settings":
+ out.Values[i] = ec._Project_settings(ctx, field, obj)
+ if out.Values[i] == graphql.Null {
+ invalids++
+ }
+ default:
+ panic("unknown field " + strconv.Quote(field.Name))
+ }
+ }
+ out.Dispatch()
+ if invalids > 0 {
+ return graphql.Null
+ }
+ return out
+}
+
+var projectSettingsImplementors = []string{"ProjectSettings"}
+
+func (ec *executionContext) _ProjectSettings(ctx context.Context, sel ast.SelectionSet, obj *ProjectSettings) graphql.Marshaler {
+ fields := graphql.CollectFields(ec.OperationContext, sel, projectSettingsImplementors)
+
+ out := graphql.NewFieldSet(fields)
+ var invalids uint32
+ for i, field := range fields {
+ switch field.Name {
+ case "__typename":
+ out.Values[i] = graphql.MarshalString("ProjectSettings")
+ case "intercept":
+ out.Values[i] = ec._ProjectSettings_intercept(ctx, field, obj)
+ if out.Values[i] == graphql.Null {
+ invalids++
+ }
default:
panic("unknown field " + strconv.Quote(field.Name))
}
@@ -6726,6 +7035,20 @@ func (ec *executionContext) marshalNInt2int(ctx context.Context, sel ast.Selecti
return res
}
+func (ec *executionContext) marshalNInterceptSettings2githubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐInterceptSettings(ctx context.Context, sel ast.SelectionSet, v InterceptSettings) graphql.Marshaler {
+ return ec._InterceptSettings(ctx, sel, &v)
+}
+
+func (ec *executionContext) marshalNInterceptSettings2ᚖgithubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐInterceptSettings(ctx context.Context, sel ast.SelectionSet, v *InterceptSettings) graphql.Marshaler {
+ if v == nil {
+ if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {
+ ec.Errorf(ctx, "must not be null")
+ }
+ return graphql.Null
+ }
+ return ec._InterceptSettings(ctx, sel, v)
+}
+
func (ec *executionContext) unmarshalNModifyRequestInput2githubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐModifyRequestInput(ctx context.Context, v interface{}) (ModifyRequestInput, error) {
res, err := ec.unmarshalInputModifyRequestInput(ctx, v)
return res, graphql.ErrorOnPath(ctx, err)
@@ -6793,6 +7116,16 @@ func (ec *executionContext) marshalNProject2ᚕgithubᚗcomᚋdstotijnᚋhetty
return ret
}
+func (ec *executionContext) marshalNProjectSettings2ᚖgithubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐProjectSettings(ctx context.Context, sel ast.SelectionSet, v *ProjectSettings) graphql.Marshaler {
+ if v == nil {
+ if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {
+ ec.Errorf(ctx, "must not be null")
+ }
+ return graphql.Null
+ }
+ return ec._ProjectSettings(ctx, sel, v)
+}
+
func (ec *executionContext) marshalNScopeRule2githubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐScopeRule(ctx context.Context, sel ast.SelectionSet, v ScopeRule) graphql.Marshaler {
return ec._ScopeRule(ctx, sel, &v)
}
@@ -6981,6 +7314,11 @@ func (ec *executionContext) marshalNURL2ᚖnetᚋurlᚐURL(ctx context.Context,
return res
}
+func (ec *executionContext) unmarshalNUpdateInterceptSettingsInput2githubᚗcomᚋdstotijnᚋhettyᚋpkgᚋapiᚐUpdateInterceptSettingsInput(ctx context.Context, v interface{}) (UpdateInterceptSettingsInput, error) {
+ res, err := ec.unmarshalInputUpdateInterceptSettingsInput(ctx, v)
+ return res, graphql.ErrorOnPath(ctx, err)
+}
+
func (ec *executionContext) marshalN__Directive2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐDirective(ctx context.Context, sel ast.SelectionSet, v introspection.Directive) graphql.Marshaler {
return ec.___Directive(ctx, sel, &v)
}
diff --git a/pkg/api/models_gen.go b/pkg/api/models_gen.go
index 09b8749..8e5c0fb 100644
--- a/pkg/api/models_gen.go
+++ b/pkg/api/models_gen.go
@@ -82,6 +82,10 @@ type HTTPResponseLog struct {
Headers []HTTPHeader `json:"headers"`
}
+type InterceptSettings struct {
+ Enabled bool `json:"enabled"`
+}
+
type ModifyRequestInput struct {
ID ulid.ULID `json:"id"`
URL *url.URL `json:"url"`
@@ -96,9 +100,14 @@ type ModifyRequestResult struct {
}
type Project struct {
- ID ulid.ULID `json:"id"`
- Name string `json:"name"`
- IsActive bool `json:"isActive"`
+ ID ulid.ULID `json:"id"`
+ Name string `json:"name"`
+ IsActive bool `json:"isActive"`
+ Settings *ProjectSettings `json:"settings"`
+}
+
+type ProjectSettings struct {
+ Intercept *InterceptSettings `json:"intercept"`
}
type ScopeHeader struct {
@@ -154,6 +163,10 @@ type SenderRequestInput struct {
Body *string `json:"body"`
}
+type UpdateInterceptSettingsInput struct {
+ Enabled bool `json:"enabled"`
+}
+
type HTTPMethod string
const (
diff --git a/pkg/api/resolvers.go b/pkg/api/resolvers.go
index 588c188..06a9d8b 100644
--- a/pkg/api/resolvers.go
+++ b/pkg/api/resolvers.go
@@ -218,6 +218,11 @@ func (r *queryResolver) ActiveProject(ctx context.Context) (*Project, error) {
ID: p.ID,
Name: p.Name,
IsActive: r.ProjectService.IsProjectActive(p.ID),
+ Settings: &ProjectSettings{
+ Intercept: &InterceptSettings{
+ Enabled: p.Settings.InterceptEnabled,
+ },
+ },
}, nil
}
@@ -590,6 +595,26 @@ func (r *mutationResolver) CancelRequest(ctx context.Context, id ulid.ULID) (*Ca
return &CancelRequestResult{Success: true}, nil
}
+func (r *mutationResolver) UpdateInterceptSettings(
+ ctx context.Context,
+ input UpdateInterceptSettingsInput,
+) (*InterceptSettings, error) {
+ settings := intercept.Settings{
+ Enabled: input.Enabled,
+ }
+
+ err := r.ProjectService.UpdateInterceptSettings(ctx, settings)
+ if errors.Is(err, proj.ErrNoProject) {
+ return nil, noActiveProjectErr(ctx)
+ } else if err != nil {
+ return nil, fmt.Errorf("could not update intercept settings: %w", err)
+ }
+
+ return &InterceptSettings{
+ Enabled: settings.Enabled,
+ }, nil
+}
+
func parseSenderRequest(req sender.Request) (SenderRequest, error) {
method := HTTPMethod(req.Method)
if method != "" && !method.IsValid() {
diff --git a/pkg/api/schema.graphql b/pkg/api/schema.graphql
index 9c4aa48..046e42d 100644
--- a/pkg/api/schema.graphql
+++ b/pkg/api/schema.graphql
@@ -30,6 +30,11 @@ type Project {
id: ID!
name: String!
isActive: Boolean!
+ settings: ProjectSettings!
+}
+
+type ProjectSettings {
+ intercept: InterceptSettings!
}
type ScopeRule {
@@ -142,6 +147,14 @@ type CancelRequestResult {
success: Boolean!
}
+input UpdateInterceptSettingsInput {
+ enabled: Boolean!
+}
+
+type InterceptSettings {
+ enabled: Boolean!
+}
+
type Query {
httpRequestLog(id: ID!): HttpRequestLog
httpRequestLogs: [HttpRequestLog!]!
@@ -172,6 +185,9 @@ type Mutation {
deleteSenderRequests: DeleteSenderRequestsResult!
modifyRequest(request: ModifyRequestInput!): ModifyRequestResult!
cancelRequest(id: ID!): CancelRequestResult!
+ updateInterceptSettings(
+ input: UpdateInterceptSettingsInput!
+ ): InterceptSettings!
}
enum HttpMethod {
diff --git a/pkg/proj/proj.go b/pkg/proj/proj.go
index e26443c..e6ba850 100644
--- a/pkg/proj/proj.go
+++ b/pkg/proj/proj.go
@@ -34,6 +34,7 @@ type Service interface {
SetScopeRules(ctx context.Context, rules []scope.Rule) error
SetRequestLogFindFilter(ctx context.Context, filter reqlog.FindRequestsFilter) error
SetSenderRequestFindFilter(ctx context.Context, filter sender.FindRequestsFilter) error
+ UpdateInterceptSettings(ctx context.Context, settings intercept.Settings) error
}
type service struct {
@@ -55,13 +56,19 @@ type Project struct {
}
type Settings struct {
+ // Request log settings
ReqLogBypassOutOfScope bool
ReqLogOnlyFindInScope bool
ReqLogSearchExpr search.Expression
+ // Intercept settings
+ InterceptEnabled bool
+
+ // Sender settings
SenderOnlyFindInScope bool
SenderSearchExpr search.Expression
+ // Scope settings
ScopeRules []scope.Rule
}
@@ -121,10 +128,12 @@ func (svc *service) CloseProject() error {
}
svc.activeProjectID = ulid.ULID{}
- svc.interceptSvc.ClearRequests()
svc.reqLogSvc.SetActiveProjectID(ulid.ULID{})
svc.reqLogSvc.SetBypassOutOfScopeRequests(false)
svc.reqLogSvc.SetFindReqsFilter(reqlog.FindRequestsFilter{})
+ svc.interceptSvc.UpdateSettings(intercept.Settings{
+ Enabled: false,
+ })
svc.senderSvc.SetActiveProjectID(ulid.ULID{})
svc.senderSvc.SetFindReqsFilter(sender.FindRequestsFilter{})
svc.scope.SetRules(nil)
@@ -157,6 +166,7 @@ func (svc *service) OpenProject(ctx context.Context, projectID ulid.ULID) (Proje
svc.activeProjectID = project.ID
+ // Request log settings.
svc.reqLogSvc.SetFindReqsFilter(reqlog.FindRequestsFilter{
ProjectID: project.ID,
OnlyInScope: project.Settings.ReqLogOnlyFindInScope,
@@ -165,6 +175,12 @@ func (svc *service) OpenProject(ctx context.Context, projectID ulid.ULID) (Proje
svc.reqLogSvc.SetBypassOutOfScopeRequests(project.Settings.ReqLogBypassOutOfScope)
svc.reqLogSvc.SetActiveProjectID(project.ID)
+ // Intercept settings.
+ svc.interceptSvc.UpdateSettings(intercept.Settings{
+ Enabled: project.Settings.InterceptEnabled,
+ })
+
+ // Sender settings.
svc.senderSvc.SetActiveProjectID(project.ID)
svc.senderSvc.SetFindReqsFilter(sender.FindRequestsFilter{
ProjectID: project.ID,
@@ -172,6 +188,7 @@ func (svc *service) OpenProject(ctx context.Context, projectID ulid.ULID) (Proje
SearchExpr: project.Settings.SenderSearchExpr,
})
+ // Scope settings.
svc.scope.SetRules(project.Settings.ScopeRules)
return project, nil
@@ -269,3 +286,21 @@ func (svc *service) SetSenderRequestFindFilter(ctx context.Context, filter sende
func (svc *service) IsProjectActive(projectID ulid.ULID) bool {
return projectID.Compare(svc.activeProjectID) == 0
}
+
+func (svc *service) UpdateInterceptSettings(ctx context.Context, settings intercept.Settings) error {
+ project, err := svc.ActiveProject(ctx)
+ if err != nil {
+ return err
+ }
+
+ project.Settings.InterceptEnabled = settings.Enabled
+
+ err = svc.repo.UpsertProject(ctx, project)
+ if err != nil {
+ return fmt.Errorf("proj: failed to update project: %w", err)
+ }
+
+ svc.interceptSvc.UpdateSettings(settings)
+
+ return nil
+}
diff --git a/pkg/proxy/intercept/intercept.go b/pkg/proxy/intercept/intercept.go
index 201b3f5..89e82e5 100644
--- a/pkg/proxy/intercept/intercept.go
+++ b/pkg/proxy/intercept/intercept.go
@@ -31,10 +31,12 @@ type Service struct {
mu *sync.RWMutex
requests map[ulid.ULID]Request
logger log.Logger
+ enabled bool
}
type Config struct {
- Logger log.Logger
+ Logger log.Logger
+ Enabled bool
}
// RequestIDs implements sort.Interface.
@@ -45,6 +47,7 @@ func NewService(cfg Config) *Service {
mu: &sync.RWMutex{},
requests: make(map[ulid.ULID]Request),
logger: cfg.Logger,
+ enabled: cfg.Enabled,
}
if s.logger == nil {
@@ -93,6 +96,12 @@ func (svc *Service) Intercept(ctx context.Context, req *http.Request) (*http.Req
return req, nil
}
+ if !svc.enabled {
+ // If intercept is disabled, return the incoming request as-is.
+ svc.logger.Debugw("Bypassed interception: module disabled.")
+ return req, nil
+ }
+
ch := make(chan *http.Request)
done := make(chan struct{})
@@ -181,6 +190,15 @@ func (svc *Service) Requests() []*http.Request {
return reqs
}
+func (svc *Service) UpdateSettings(settings Settings) {
+ // When updating from `enabled` -> `disabled`, clear any pending reqs.
+ if svc.enabled && !settings.Enabled {
+ svc.ClearRequests()
+ }
+
+ svc.enabled = settings.Enabled
+}
+
// Request returns an intercepted request by ID. It's safe for concurrent use.
func (svc *Service) RequestByID(id ulid.ULID) (*http.Request, error) {
svc.mu.RLock()
diff --git a/pkg/proxy/intercept/intercept_test.go b/pkg/proxy/intercept/intercept_test.go
index 77b794c..fe683bd 100644
--- a/pkg/proxy/intercept/intercept_test.go
+++ b/pkg/proxy/intercept/intercept_test.go
@@ -28,7 +28,8 @@ func TestRequestModifier(t *testing.T) {
logger, _ := zap.NewDevelopment()
svc := intercept.NewService(intercept.Config{
- Logger: logger.Sugar(),
+ Logger: logger.Sugar(),
+ Enabled: true,
})
reqID := ulid.MustNew(ulid.Timestamp(time.Now()), ulidEntropy)
@@ -44,7 +45,8 @@ func TestRequestModifier(t *testing.T) {
logger, _ := zap.NewDevelopment()
svc := intercept.NewService(intercept.Config{
- Logger: logger.Sugar(),
+ Logger: logger.Sugar(),
+ Enabled: true,
})
ctx, cancel := context.WithCancel(context.Background())
@@ -65,7 +67,7 @@ func TestRequestModifier(t *testing.T) {
err := svc.ModifyRequest(reqID, nil)
if !errors.Is(err, intercept.ErrRequestDone) {
- t.Fatalf("expected `interept.ErrRequestDone`, got: %v", err)
+ t.Fatalf("expected `intercept.ErrRequestDone`, got: %v", err)
}
})
@@ -83,7 +85,8 @@ func TestRequestModifier(t *testing.T) {
logger, _ := zap.NewDevelopment()
svc := intercept.NewService(intercept.Config{
- Logger: logger.Sugar(),
+ Logger: logger.Sugar(),
+ Enabled: true,
})
var got *http.Request
diff --git a/pkg/proxy/intercept/settings.go b/pkg/proxy/intercept/settings.go
new file mode 100644
index 0000000..35ac2fc
--- /dev/null
+++ b/pkg/proxy/intercept/settings.go
@@ -0,0 +1,5 @@
+package intercept
+
+type Settings struct {
+ Enabled bool
+}