Monorepo for Tangled tangled.org

appview: repo/new: additional checks for repo names

avoids path traversal attempts.

authored by oppi.li and committed by Tangled e705ed86 983d8d2e

Changed files
+35 -10
appview
state
+35 -10
appview/state/state.go
··· 601 601 func (s *State) RemoveMember(w http.ResponseWriter, r *http.Request) { 602 602 } 603 603 604 + func validateRepoName(name string) error { 605 + // check for path traversal attempts 606 + if name == "." || name == ".." || 607 + strings.Contains(name, "/") || strings.Contains(name, "\\") { 608 + return fmt.Errorf("Repository name contains invalid path characters") 609 + } 610 + 611 + // check for sequences that could be used for traversal when normalized 612 + if strings.Contains(name, "./") || strings.Contains(name, "../") || 613 + strings.HasPrefix(name, ".") || strings.HasSuffix(name, ".") { 614 + return fmt.Errorf("Repository name contains invalid path sequence") 615 + } 616 + 617 + // then continue with character validation 618 + for _, char := range name { 619 + if !((char >= 'a' && char <= 'z') || 620 + (char >= 'A' && char <= 'Z') || 621 + (char >= '0' && char <= '9') || 622 + char == '-' || char == '_' || char == '.') { 623 + return fmt.Errorf("Repository name can only contain alphanumeric characters, periods, hyphens, and underscores") 624 + } 625 + } 626 + 627 + // additional check to prevent multiple sequential dots 628 + if strings.Contains(name, "..") { 629 + return fmt.Errorf("Repository name cannot contain sequential dots") 630 + } 631 + 632 + // if all checks pass 633 + return nil 634 + } 635 + 604 636 func (s *State) NewRepo(w http.ResponseWriter, r *http.Request) { 605 637 ctx, span := s.t.TraceStart(r.Context(), "NewRepo") 606 638 defer span.End() ··· 643 675 } 644 676 span.SetAttributes(attribute.String("repo.name", repoName)) 645 677 646 - // Check for valid repository name (GitHub-like rules) 647 - // No spaces, only alphanumeric characters, dashes, and underscores 648 - for _, char := range repoName { 649 - if !((char >= 'a' && char <= 'z') || 650 - (char >= 'A' && char <= 'Z') || 651 - (char >= '0' && char <= '9') || 652 - char == '-' || char == '_' || char == '.') { 653 - s.pages.Notice(w, "repo", "Repository name can only contain alphanumeric characters, periods, hyphens, and underscores.") 654 - return 655 - } 678 + if err := validateRepoName(repoName); err != nil { 679 + s.pages.Notice(w, "repo", err.Error()) 680 + return 656 681 } 657 682 658 683 defaultBranch := r.FormValue("branch")