|
1 | 1 | // Copyright (c) 2015-2023 Jeevanandam M ([email protected])
|
2 | 2 | // 2023 Segev Dagan (https://github.com/segevda)
|
| 3 | +// 2024 Philipp Wolfer (https://github.com/phw) |
3 | 4 | // All rights reserved.
|
4 | 5 | // resty source code and usage is governed by a MIT style
|
5 | 6 | // license that can be found in the LICENSE file.
|
@@ -125,48 +126,78 @@ type challenge struct {
|
125 | 126 | userhash string
|
126 | 127 | }
|
127 | 128 |
|
| 129 | +func (c *challenge) setValue(k, v string) error { |
| 130 | + switch k { |
| 131 | + case "realm": |
| 132 | + c.realm = v |
| 133 | + case "domain": |
| 134 | + c.domain = v |
| 135 | + case "nonce": |
| 136 | + c.nonce = v |
| 137 | + case "opaque": |
| 138 | + c.opaque = v |
| 139 | + case "stale": |
| 140 | + c.stale = v |
| 141 | + case "algorithm": |
| 142 | + c.algorithm = v |
| 143 | + case "qop": |
| 144 | + c.qop = v |
| 145 | + case "charset": |
| 146 | + if strings.ToUpper(v) != "UTF-8" { |
| 147 | + return ErrDigestCharset |
| 148 | + } |
| 149 | + case "userhash": |
| 150 | + c.userhash = v |
| 151 | + default: |
| 152 | + return ErrDigestBadChallenge |
| 153 | + } |
| 154 | + return nil |
| 155 | +} |
| 156 | + |
128 | 157 | func parseChallenge(input string) (*challenge, error) {
|
129 | 158 | const ws = " \n\r\t"
|
130 |
| - const qs = `"` |
131 | 159 | s := strings.Trim(input, ws)
|
132 | 160 | if !strings.HasPrefix(s, "Digest ") {
|
133 | 161 | return nil, ErrDigestBadChallenge
|
134 | 162 | }
|
135 | 163 | s = strings.Trim(s[7:], ws)
|
136 |
| - sl := strings.Split(s, ",") |
137 | 164 | c := &challenge{}
|
138 |
| - var r []string |
139 |
| - for i := range sl { |
140 |
| - sl[i] = strings.TrimSpace(sl[i]) |
141 |
| - r = strings.SplitN(sl[i], "=", 2) |
142 |
| - if len(r) != 2 { |
143 |
| - return nil, ErrDigestBadChallenge |
144 |
| - } |
145 |
| - r[0] = strings.TrimSpace(r[0]) |
146 |
| - r[1] = strings.TrimSpace(r[1]) |
147 |
| - switch r[0] { |
148 |
| - case "realm": |
149 |
| - c.realm = strings.Trim(r[1], qs) |
150 |
| - case "domain": |
151 |
| - c.domain = strings.Trim(r[1], qs) |
152 |
| - case "nonce": |
153 |
| - c.nonce = strings.Trim(r[1], qs) |
154 |
| - case "opaque": |
155 |
| - c.opaque = strings.Trim(r[1], qs) |
156 |
| - case "stale": |
157 |
| - c.stale = strings.Trim(r[1], qs) |
158 |
| - case "algorithm": |
159 |
| - c.algorithm = strings.Trim(r[1], qs) |
160 |
| - case "qop": |
161 |
| - c.qop = strings.Trim(r[1], qs) |
162 |
| - case "charset": |
163 |
| - if strings.ToUpper(strings.Trim(r[1], qs)) != "UTF-8" { |
164 |
| - return nil, ErrDigestCharset |
| 165 | + b := strings.Builder{} |
| 166 | + key := "" |
| 167 | + quoted := false |
| 168 | + for _, r := range s { |
| 169 | + switch r { |
| 170 | + case '"': |
| 171 | + quoted = !quoted |
| 172 | + case ',': |
| 173 | + if quoted { |
| 174 | + b.WriteRune(r) |
| 175 | + } else { |
| 176 | + val := strings.Trim(b.String(), ws) |
| 177 | + b.Reset() |
| 178 | + if err := c.setValue(key, val); err != nil { |
| 179 | + return nil, err |
| 180 | + } |
| 181 | + key = "" |
| 182 | + } |
| 183 | + case '=': |
| 184 | + if quoted { |
| 185 | + b.WriteRune(r) |
| 186 | + } else { |
| 187 | + key = strings.Trim(b.String(), ws) |
| 188 | + b.Reset() |
165 | 189 | }
|
166 |
| - case "userhash": |
167 |
| - c.userhash = strings.Trim(r[1], qs) |
168 | 190 | default:
|
169 |
| - return nil, ErrDigestBadChallenge |
| 191 | + b.WriteRune(r) |
| 192 | + } |
| 193 | + } |
| 194 | + if quoted || (key == "" && b.Len() > 0) { |
| 195 | + return nil, ErrDigestBadChallenge |
| 196 | + } |
| 197 | + if key != "" { |
| 198 | + val := strings.Trim(b.String(), ws) |
| 199 | + if err := c.setValue(key, val); err != nil { |
| 200 | + return nil, err |
170 | 201 | }
|
171 | 202 | }
|
172 | 203 | return c, nil
|
@@ -233,9 +264,10 @@ func (c *credentials) validateQop() error {
|
233 | 264 | if c.messageQop == "" {
|
234 | 265 | return ErrDigestNoQop
|
235 | 266 | }
|
236 |
| - possibleQops := strings.Split(c.messageQop, ", ") |
| 267 | + possibleQops := strings.Split(c.messageQop, ",") |
237 | 268 | var authSupport bool
|
238 | 269 | for _, qop := range possibleQops {
|
| 270 | + qop = strings.TrimSpace(qop) |
239 | 271 | if qop == "auth" {
|
240 | 272 | authSupport = true
|
241 | 273 | break
|
|
0 commit comments