| 234 | } |
| 235 | |
| 236 | func (v *Validator) ValidateSectorIdentifierURL(ctx context.Context, location string, redirectURIs []string) error { |
| 237 | l, err := url.Parse(location) |
| 238 | if err != nil { |
| 239 | return errors.WithStack(ErrInvalidClientMetadata.WithHintf("Value of sector_identifier_uri could not be parsed because %s.", err)) |
| 240 | } |
| 241 | |
| 242 | if l.Scheme != "https" { |
| 243 | return errors.WithStack(ErrInvalidClientMetadata.WithDebug("Value sector_identifier_uri must be an HTTPS URL but it is not.")) |
| 244 | } |
| 245 | |
| 246 | req, err := retryablehttp.NewRequestWithContext(ctx, "GET", location, nil) |
| 247 | if err != nil { |
| 248 | return errors.WithStack(ErrInvalidClientMetadata.WithDebugf("Value sector_identifier_uri must be an HTTPS URL but it is not: %s", err.Error())) |
| 249 | } |
| 250 | response, err := v.r.HTTPClient(ctx).Do(req) |
| 251 | if err != nil { |
| 252 | return errors.WithStack(ErrInvalidClientMetadata.WithDebug(fmt.Sprintf("Unable to connect to URL set by sector_identifier_uri: %s", err))) |
| 253 | } |
| 254 | defer response.Body.Close() //nolint:errcheck |
| 255 | response.Body = io.NopCloser(io.LimitReader(response.Body, 5<<20 /* 5 MiB */)) |
| 256 | |
| 257 | var urls []string |
| 258 | if err := json.NewDecoder(response.Body).Decode(&urls); err != nil { |
| 259 | return errors.WithStack(ErrInvalidClientMetadata.WithDebug(fmt.Sprintf("Unable to decode values from sector_identifier_uri: %s", err))) |
| 260 | } |
| 261 | |
| 262 | if len(urls) == 0 { |
| 263 | return errors.WithStack(ErrInvalidClientMetadata.WithDebug("Array from sector_identifier_uri contains no items")) |
| 264 | } |
| 265 | |
| 266 | for _, r := range redirectURIs { |
| 267 | if !slices.Contains(urls, r) { |
| 268 | return errors.WithStack(ErrInvalidClientMetadata.WithDebug(fmt.Sprintf("Redirect URL \"%s\" does not match values from sector_identifier_uri.", r))) |
| 269 | } |
| 270 | } |
| 271 | |
| 272 | return nil |
| 273 | } |