Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions networkrules/rule/rule.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,8 @@ func (rm *Rule) ParseModifiers(modifiers []string) error {
modifier = &rulemodifiers.ScrambleJSModifier{}
case isKind("jsonprune"):
modifier = &rulemodifiers.JSONPruneModifier{}
case isKind("csp"):
modifier = &rulemodifiers.CSPModifier{}
case isKind("all"):
// TODO: should act as "popup" modifier once it gets implemented
continue
Expand Down
44 changes: 44 additions & 0 deletions networkrules/rulemodifiers/csp.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package rulemodifiers

import (
"errors"
"net/http"
"strings"
)

type CSPModifier struct {
policy string
}

var _ ModifyingModifier = (*CSPModifier)(nil)

func (m *CSPModifier) Parse(modifier string) error {
if !strings.HasPrefix(modifier, "csp=") {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

$csp exception modifiers can exist without a value, such as this example from this filter list:

@@||lewd.ninja^$csp

We need to handle this case as well, by:

  • Allowing modifiers without a value in Parse, leaving policy as an empty string
  • In ModifyRes, skipping modifier application when policy in an empty string
  • In Cancels, always canceling the other policy if m.policy == ""; otherwise, comparing policies for full equality
  • Adding the modifier to exceptionrule.go

return errors.New("invalid csp modifier")
}
m.policy = strings.TrimPrefix(modifier, "csp=")
if m.policy == "" {
return errors.New("empty csp policy")
}
return nil
}

func (m *CSPModifier) ModifyReq(req *http.Request) bool {
// CSP is a response header, so we do nothing to the request.
return false
}

func (m *CSPModifier) ModifyRes(res *http.Response) (bool, error) {
// We use Add() instead of Set() because if the site already has a CSP,
// browsers enforce the "intersection" of all policies (most restrictive wins).
res.Header.Add("Content-Security-Policy", m.policy)
return true, nil
}

func (m *CSPModifier) Cancels(modifier Modifier) bool {
other, ok := modifier.(*CSPModifier)
if !ok {
return false
}
return m.policy == other.policy
}