(selector string)
| 585 | } |
| 586 | |
| 587 | func normalizeHashSelector(selector string) string { |
| 588 | token := strings.TrimSpace(selector) |
| 589 | if token == "" { |
| 590 | return "" |
| 591 | } |
| 592 | |
| 593 | if parsed, err := url.Parse(token); err == nil && parsed.Host != "" { |
| 594 | if q := strings.TrimSpace(parsed.Query().Get("hash")); isLikelyHash(q) { |
| 595 | return q |
| 596 | } |
| 597 | path := strings.Trim(parsed.Path, "/") |
| 598 | if path == "" { |
| 599 | return "" |
| 600 | } |
| 601 | parts := strings.Split(path, "/") |
| 602 | for i := 0; i < len(parts); i++ { |
| 603 | if parts[i] == "hash" && i+1 < len(parts) && isLikelyHash(parts[i+1]) { |
| 604 | return parts[i+1] |
| 605 | } |
| 606 | } |
| 607 | last := parts[len(parts)-1] |
| 608 | if isLikelyHash(last) { |
| 609 | return last |
| 610 | } |
| 611 | return "" |
| 612 | } |
| 613 | |
| 614 | token = strings.Trim(token, "/") |
| 615 | if strings.Contains(token, "/") { |
| 616 | parts := strings.Split(token, "/") |
| 617 | token = parts[len(parts)-1] |
| 618 | } |
| 619 | if !isLikelyHash(token) { |
| 620 | return "" |
| 621 | } |
| 622 | return token |
| 623 | } |
| 624 | |
| 625 | func isLikelyHash(value string) bool { |
| 626 | if value == "" { |
no test coverage detected