github.com/khulnasoft-lab/tunnel-db@v0.0.0-20231117205118-74e1113bd007/pkg/vulnsrc/osv/range.go (about) 1 package osv 2 3 import ( 4 "fmt" 5 6 mvn "github.com/masahiro331/go-mvn-version" 7 "golang.org/x/xerrors" 8 9 "github.com/khulnasoft-lab/go-gem-version" 10 "github.com/khulnasoft-lab/go-npm-version/pkg" 11 pep440 "github.com/khulnasoft-lab/go-pep440-version" 12 "github.com/khulnasoft-lab/goversion/pkg/semver" 13 "github.com/khulnasoft-lab/goversion/pkg/version" 14 ) 15 16 type VersionRange interface { 17 Contains(ver string) (bool, error) 18 String() string 19 SetFixed(fixed string) 20 SetLastAffected(lastAffected string) 21 } 22 23 func NewVersionRange(ecosystem Ecosystem, from string) VersionRange { 24 vr := &versionRange{from: from} 25 switch ecosystem { 26 case EcosystemNpm: 27 return &NpmVersionRange{versionRange: vr} 28 case EcosystemRubygems: 29 return &RubyGemsVersionRange{versionRange: vr} 30 case EcosystemPyPI: 31 return &PyPIVersionRange{versionRange: vr} 32 case EcosystemMaven: 33 return &MavenVersionRange{versionRange: vr} 34 case EcosystemGo, EcosystemCrates, EcosystemNuGet: 35 return &SemVerRange{versionRange: vr} 36 case EcosystemPackagist: 37 return &DefaultVersionRange{versionRange: vr} 38 default: 39 return &DefaultVersionRange{versionRange: vr} 40 } 41 } 42 43 // versionRange represents a range of versions 44 type versionRange struct { 45 from string 46 to string 47 toIncluded bool 48 } 49 50 // constraint returns the range as a constraint string in the expected 51 // format for semver.NewConstraint 52 func (r *versionRange) String() string { 53 // e.g. {"introduced": "1.2.0"}, {"last_affected": "1.2.0"} 54 if r.toIncluded && r.from == r.to { 55 return fmt.Sprintf("=%s", r.from) 56 } 57 58 var ver string 59 if r.to != "" { 60 ver = fmt.Sprintf("<%s", r.to) 61 if r.toIncluded { 62 ver = fmt.Sprintf("<=%s", r.to) 63 } 64 } 65 66 if ver == "" { 67 return fmt.Sprintf(">=%s", r.from) 68 } 69 70 // ">=0" can be omitted. 71 // e.g. {"introduced": "0", "fixed": "1.2.3"} => "<1.2.3" 72 if r.from == "0" { 73 return ver 74 } 75 76 return fmt.Sprintf(">=%s, %s", r.from, ver) 77 } 78 79 func (r *versionRange) SetFixed(fixed string) { 80 r.to = fixed 81 r.toIncluded = false 82 } 83 84 func (r *versionRange) SetLastAffected(lastAffected string) { 85 r.to = lastAffected 86 r.toIncluded = true 87 } 88 89 type DefaultVersionRange struct { 90 *versionRange 91 } 92 93 func (r *DefaultVersionRange) Contains(ver string) (bool, error) { 94 c, err := version.NewConstraints(r.String()) 95 if err != nil { 96 return false, xerrors.Errorf("failed to parse version constraint: %w", err) 97 } 98 99 v, err := version.Parse(ver) 100 if err != nil { 101 return false, xerrors.Errorf("failed to parse version: %w", err) 102 } 103 104 return c.Check(v), nil 105 } 106 107 type SemVerRange struct { 108 *versionRange 109 } 110 111 func (r *SemVerRange) Contains(ver string) (bool, error) { 112 c, err := semver.NewConstraints(r.String()) 113 if err != nil { 114 return false, xerrors.Errorf("failed to parse version constraint: %w", err) 115 } 116 117 v, err := semver.Parse(ver) 118 if err != nil { 119 return false, xerrors.Errorf("failed to parse version: %w", err) 120 } 121 122 return c.Check(v), nil 123 } 124 125 type NpmVersionRange struct { 126 *versionRange 127 } 128 129 func (r *NpmVersionRange) Contains(ver string) (bool, error) { 130 c, err := npm.NewConstraints(r.String()) 131 if err != nil { 132 return false, xerrors.Errorf("failed to parse version constraint: %w", err) 133 } 134 135 v, err := npm.NewVersion(ver) 136 if err != nil { 137 return false, xerrors.Errorf("failed to parse version: %w", err) 138 } 139 140 return c.Check(v), nil 141 } 142 143 type RubyGemsVersionRange struct { 144 *versionRange 145 } 146 147 func (r *RubyGemsVersionRange) Contains(ver string) (bool, error) { 148 c, err := gem.NewConstraints(r.String()) 149 if err != nil { 150 return false, xerrors.Errorf("failed to parse version constraint: %w", err) 151 } 152 153 v, err := gem.NewVersion(ver) 154 if err != nil { 155 return false, xerrors.Errorf("failed to parse version: %w", err) 156 } 157 158 return c.Check(v), nil 159 } 160 161 type PyPIVersionRange struct { 162 *versionRange 163 } 164 165 func (r *PyPIVersionRange) Contains(ver string) (bool, error) { 166 c, err := pep440.NewSpecifiers(r.String()) 167 if err != nil { 168 return false, xerrors.Errorf("failed to parse version constraint: %w", err) 169 } 170 171 v, err := pep440.Parse(ver) 172 if err != nil { 173 return false, xerrors.Errorf("failed to parse version: %w", err) 174 } 175 176 return c.Check(v), nil 177 } 178 179 type MavenVersionRange struct { 180 *versionRange 181 } 182 183 func (r *MavenVersionRange) Contains(ver string) (bool, error) { 184 c, err := mvn.NewConstraints(r.String()) 185 if err != nil { 186 return false, xerrors.Errorf("failed to parse version constraint: %w", err) 187 } 188 189 v, err := mvn.NewVersion(ver) 190 if err != nil { 191 return false, xerrors.Errorf("failed to parse version: %w", err) 192 } 193 194 return c.Check(v), nil 195 }