Skip to content

Commit 1ebf01f

Browse files
authored
Merge pull request #11 from quix-labs/feature/security_addon
add security constraints values + range
2 parents 26a045a + 2a4e384 commit 1ebf01f

File tree

6 files changed

+416
-21
lines changed

6 files changed

+416
-21
lines changed

README.md

Lines changed: 44 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -155,16 +155,52 @@ This gives you fine-grained control over image processing in your Caddy server.
155155

156156
### Example with `on_fail` and Security Configuration
157157
```plaintext
158-
localhost {
159-
image_processor {
160-
on_fail bypass # Default value
158+
localhost:80 {
159+
import common
160+
root test-dataset
161+
file_server
162+
image_processor {
163+
164+
# Serve original image if image in unprocessable
165+
on_fail bypass
166+
167+
# Return 500 Internal Server Error if processing fails
168+
# on_fail abort
169+
170+
161171
security {
162-
on_security_fail ignore # Default value
172+
173+
# Use ignore to remove param from processing, all valid param are processed
174+
on_security_fail ignore
175+
176+
# Use abort to return 400 Bad Request when fails
177+
# on_security_fail abort
178+
179+
# Use bypass to serve original image without processing
180+
# on_security_fail bypass
181+
182+
# Explicitely disable rotate capabilities
183+
disallowed_params r
163184
164-
disallowed_params w r ... # These parameters are disallowed in the image processing request. You can also use allowed_params to restrict parameters further.
165-
# Note: 'allowed_params' and 'disallowed_params' cannot be used together. You must choose one or the other.
185+
# As an alternative use this to only accept width and height processing
186+
# allowed_params w h
187+
188+
constraints {
189+
h range 60 480
190+
191+
w {
192+
values 60 130 240 480 637
193+
194+
# Shortcut range 60 637
195+
range {
196+
from 60
197+
to 637
198+
}
199+
}
200+
201+
}
166202
}
167-
}
203+
}
168204
}
169205
```
170206

@@ -189,6 +225,7 @@ localhost {
189225
* `allowed_params`: Specify which query parameters are allowed. As an alternative to `disallowed_params`.
190226

191227
* **Important**: You cannot use both allowed_params and disallowed_params in the same configuration.
228+
* `constraints`: You san specify constraints for each parameter (see example)
192229

193230

194231
## Planned Features

constraint_range.go

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
package CADDY_FILE_SERVER
2+
3+
import (
4+
"fmt"
5+
"github.com/caddyserver/caddy/v2/caddyconfig/caddyfile"
6+
"slices"
7+
"strconv"
8+
)
9+
10+
func init() {
11+
RegisterConstraintType(func() Constraint {
12+
return new(RangeConstraint)
13+
})
14+
}
15+
16+
type RangeConstraint struct {
17+
From int `json:"from,omitempty"`
18+
To int `json:"to,omitempty"`
19+
}
20+
21+
func (r *RangeConstraint) ID() string {
22+
return "range"
23+
}
24+
25+
func (r *RangeConstraint) Validate(param string) error {
26+
if !slices.Contains([]string{"w", "h", "q", "ah", "aw", "t", "l", "r", "b"}, param) {
27+
return fmt.Errorf("range constraint cannot be applied on param: '%s'", param)
28+
}
29+
if r.From < 0 {
30+
return fmt.Errorf("range constraint must have minimum value less than 0")
31+
}
32+
if r.From >= r.To {
33+
return fmt.Errorf("range constraint must have minimum value less than max")
34+
}
35+
return nil
36+
}
37+
38+
func (r *RangeConstraint) ValidateParam(param string, value string) error {
39+
intValue, err := strconv.Atoi(value)
40+
if err != nil {
41+
return fmt.Errorf("invalid integer value for %s: %s", param, value)
42+
}
43+
44+
if intValue < r.From || intValue > r.To {
45+
return fmt.Errorf("%s must be in range %d to %d", param, r.From, r.To)
46+
}
47+
48+
return nil
49+
}
50+
51+
func (r *RangeConstraint) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
52+
var nested bool
53+
54+
// Try to load nested block if present
55+
for nesting := d.Nesting(); d.NextBlock(nesting); {
56+
nested = true
57+
param := d.Val()
58+
59+
switch param {
60+
case "from":
61+
if !d.NextArg() {
62+
return d.Err("missing value for from")
63+
}
64+
var err error
65+
r.From, err = strconv.Atoi(d.Val())
66+
if err != nil {
67+
return d.Errf("invalid from value for range: %v", err)
68+
}
69+
case "to":
70+
if !d.NextArg() {
71+
return d.Err("missing value for to")
72+
}
73+
var err error
74+
r.To, err = strconv.Atoi(d.Val())
75+
if err != nil {
76+
return d.Errf("invalid to value for range: %v", err)
77+
}
78+
default:
79+
return d.Errf("unexpected parameter '%s' in range constraint", param)
80+
}
81+
}
82+
83+
// If not a nested block, process inline arguments
84+
if !nested {
85+
if !d.NextArg() {
86+
return d.Err("missing from value for range constraint")
87+
}
88+
var err error
89+
r.From, err = strconv.Atoi(d.Val())
90+
if err != nil {
91+
return d.Errf("invalid from value for range: %v", err)
92+
}
93+
94+
if !d.NextArg() {
95+
return d.Err("missing to value for range constraint")
96+
}
97+
r.To, err = strconv.Atoi(d.Val())
98+
if err != nil {
99+
return d.Errf("invalid to value for range: %v", err)
100+
}
101+
102+
if d.NextArg() {
103+
return d.ArgErr()
104+
}
105+
}
106+
return nil
107+
}

constraint_values.go

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
package CADDY_FILE_SERVER
2+
3+
import (
4+
"errors"
5+
"fmt"
6+
"github.com/caddyserver/caddy/v2/caddyconfig/caddyfile"
7+
"slices"
8+
"strconv"
9+
)
10+
11+
func init() {
12+
RegisterConstraintType(func() Constraint {
13+
return new(ValuesConstraint)
14+
})
15+
}
16+
17+
type ValuesConstraint struct {
18+
Values []int `json:"values"`
19+
}
20+
21+
func (r *ValuesConstraint) ID() string {
22+
return "values"
23+
}
24+
25+
func (r *ValuesConstraint) Validate(param string) error {
26+
if !slices.Contains([]string{"w", "h", "q", "ah", "aw", "t", "l", "r", "b"}, param) {
27+
return fmt.Errorf("values constraint cannot be applied on param: '%s'", param)
28+
}
29+
if len(r.Values) == 0 {
30+
return errors.New("you need to provide at least one value for values constraint")
31+
}
32+
return nil
33+
}
34+
35+
func (r *ValuesConstraint) ValidateParam(param string, value string) error {
36+
intValue, err := strconv.Atoi(value)
37+
if err != nil {
38+
return fmt.Errorf("invalid integer value for %s: %s", param, value)
39+
}
40+
41+
if !slices.Contains(r.Values, intValue) {
42+
return fmt.Errorf("parameter %s has an invalid value: %d", param, intValue)
43+
}
44+
45+
return nil
46+
}
47+
48+
func (r *ValuesConstraint) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
49+
values := d.RemainingArgs()
50+
r.Values = make([]int, len(values))
51+
for idx, v := range values {
52+
var err error
53+
if r.Values[idx], err = strconv.Atoi(v); err != nil {
54+
return err
55+
}
56+
}
57+
58+
return nil
59+
}

0 commit comments

Comments
 (0)