srdusr
aboutsummaryrefslogtreecommitdiffstats
path: root/internal/ipc
diff options
context:
space:
mode:
Diffstat (limited to 'internal/ipc')
-rw-r--r--internal/ipc/ipc.go65
-rw-r--r--internal/ipc/server.go41
2 files changed, 104 insertions, 2 deletions
diff --git a/internal/ipc/ipc.go b/internal/ipc/ipc.go
index f890715..19c9c23 100644
--- a/internal/ipc/ipc.go
+++ b/internal/ipc/ipc.go
@@ -11,12 +11,13 @@ import (
"net"
"sync"
+ "mitmux/internal/rules"
"mitmux/internal/store"
)
// Request is sent by a client to the daemon.
type Request struct {
- Type string `json:"type"` // "list", "get", "subscribe", or "repeat"
+ Type string `json:"type"` // "list", "get", "subscribe", "repeat", "rules_list", "rules_save", "rules_delete", or "rules_toggle"
Limit int `json:"limit,omitempty"`
BeforeID int64 `json:"before_id,omitempty"`
ID int64 `json:"id,omitempty"`
@@ -30,14 +31,22 @@ type Request struct {
Scheme string `json:"scheme,omitempty"`
Host string `json:"host,omitempty"`
Raw []byte `json:"raw,omitempty"`
+
+ // For "rules_save": add (Rule.ID == 0) or update (Rule.ID != 0) a
+ // match-and-replace rule. For "rules_delete"/"rules_toggle": RuleID
+ // (and RuleEnabled for toggle) identify the target.
+ Rule *rules.Rule `json:"rule,omitempty"`
+ RuleID int64 `json:"rule_id,omitempty"`
+ RuleEnabled bool `json:"rule_enabled,omitempty"`
}
// Response is sent by the daemon to a client.
type Response struct {
- Type string `json:"type"` // "list", "get", "new", "repeat", or "error"
+ Type string `json:"type"` // "list", "get", "new", "repeat", "rules", or "error"
Entries []store.Summary `json:"entries,omitempty"` // for "list"
Detail *EntryDetail `json:"detail,omitempty"` // for "get" and "repeat"
New *store.Summary `json:"new,omitempty"` // for "new" (subscribe push)
+ Rules []rules.Rule `json:"rules,omitempty"` // for "rules"
Error string `json:"error,omitempty"`
}
@@ -144,6 +153,58 @@ func (c *Client) Repeat(scheme, host string, raw []byte) (*EntryDetail, error) {
return resp.Detail, nil
}
+// ListRules returns every match-and-replace rule.
+func (c *Client) ListRules() ([]rules.Rule, error) {
+ c.mu.Lock()
+ defer c.mu.Unlock()
+ return c.rulesRoundTrip(Request{Type: "rules_list"})
+}
+
+// SaveRule adds r (if r.ID == 0) or updates the existing rule with that
+// ID, and returns its ID.
+func (c *Client) SaveRule(r rules.Rule) (int64, error) {
+ c.mu.Lock()
+ defer c.mu.Unlock()
+ saved, err := c.rulesRoundTrip(Request{Type: "rules_save", Rule: &r})
+ if err != nil {
+ return 0, err
+ }
+ if len(saved) == 0 {
+ return 0, errors.New("rules_save: daemon returned no rule")
+ }
+ return saved[0].ID, nil
+}
+
+// DeleteRule removes a rule.
+func (c *Client) DeleteRule(id int64) error {
+ c.mu.Lock()
+ defer c.mu.Unlock()
+ _, err := c.rulesRoundTrip(Request{Type: "rules_delete", RuleID: id})
+ return err
+}
+
+// SetRuleEnabled toggles a rule without touching its other fields.
+func (c *Client) SetRuleEnabled(id int64, enabled bool) error {
+ c.mu.Lock()
+ defer c.mu.Unlock()
+ _, err := c.rulesRoundTrip(Request{Type: "rules_toggle", RuleID: id, RuleEnabled: enabled})
+ return err
+}
+
+func (c *Client) rulesRoundTrip(req Request) ([]rules.Rule, error) {
+ if err := c.enc.Encode(req); err != nil {
+ return nil, err
+ }
+ var resp Response
+ if err := c.dec.Decode(&resp); err != nil {
+ return nil, err
+ }
+ if resp.Type == "error" {
+ return nil, errors.New(resp.Error)
+ }
+ return resp.Rules, nil
+}
+
// Subscribe opens a dedicated connection that streams newly captured
// history entries as they happen. The returned channel is closed when
// the connection ends; call the returned close func to stop early.
diff --git a/internal/ipc/server.go b/internal/ipc/server.go
index 69044af..1fe8d8f 100644
--- a/internal/ipc/server.go
+++ b/internal/ipc/server.go
@@ -8,6 +8,7 @@ import (
"net"
"sync"
+ "mitmux/internal/rules"
"mitmux/internal/store"
)
@@ -127,6 +128,46 @@ func (s *Server) handleConn(conn net.Conn) {
}
enc.Encode(Response{Type: "repeat", Detail: detailFromEntry(e)})
+ case "rules_list":
+ rs, err := s.db.ListRules()
+ if err != nil {
+ enc.Encode(Response{Type: "error", Error: err.Error()})
+ continue
+ }
+ enc.Encode(Response{Type: "rules", Rules: rs})
+
+ case "rules_save":
+ if req.Rule == nil {
+ enc.Encode(Response{Type: "error", Error: "rules_save: missing rule"})
+ continue
+ }
+ r := *req.Rule
+ var err error
+ if r.ID == 0 {
+ r.ID, err = s.db.AddRule(r)
+ } else {
+ err = s.db.UpdateRule(r)
+ }
+ if err != nil {
+ enc.Encode(Response{Type: "error", Error: err.Error()})
+ continue
+ }
+ enc.Encode(Response{Type: "rules", Rules: []rules.Rule{r}})
+
+ case "rules_delete":
+ if err := s.db.DeleteRule(req.RuleID); err != nil {
+ enc.Encode(Response{Type: "error", Error: err.Error()})
+ continue
+ }
+ enc.Encode(Response{Type: "rules"})
+
+ case "rules_toggle":
+ if err := s.db.SetRuleEnabled(req.RuleID, req.RuleEnabled); err != nil {
+ enc.Encode(Response{Type: "error", Error: err.Error()})
+ continue
+ }
+ enc.Encode(Response{Type: "rules"})
+
case "subscribe":
sub := s.hub.subscribe()
defer s.hub.unsubscribe(sub)