Skip to content

Commit

Permalink
Add checks for local, http & https and GitHub repository links for NPM (
Browse files Browse the repository at this point in the history
  • Loading branch information
joohoi authored Feb 17, 2021
1 parent 99de16d commit ca69ed9
Show file tree
Hide file tree
Showing 2 changed files with 73 additions and 14 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
- main
- New
- npm: In case package was found, also check if all the package versions have been unpublished. This makes the package vulnerable to takeover
- npm: Check for http & https and GitHub version references
- Changed

- v0.3
Expand Down
86 changes: 72 additions & 14 deletions npm.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"fmt"
"io/ioutil"
"net/http"
"strings"
"time"
)

Expand Down Expand Up @@ -47,13 +48,18 @@ func (n *NpmResponse) NotAvailable() bool {

// NPMLookup represents a collection of npm packages to be tested for dependency confusion.
type NPMLookup struct {
Packages []string
Packages []NPMPackage
Verbose bool
}

type NPMPackage struct {
Name string
Version string
}

// NewNPMLookup constructs an `NPMLookup` struct and returns it.
func NewNPMLookup(verbose bool) PackageResolver {
return &NPMLookup{Packages: []string{}, Verbose: verbose}
return &NPMLookup{Packages: []NPMPackage{}, Verbose: verbose}
}

// ReadPackagesFromFile reads package information from an npm package.json file
Expand All @@ -69,20 +75,24 @@ func (n *NPMLookup) ReadPackagesFromFile(filename string) error {
if err != nil {
fmt.Printf(" [W] Non-fatal issue encountered while reading %s : %s\n", filename, err)
}
for pkgname := range data.Dependencies {
n.Packages = append(n.Packages, pkgname)
for pkgname, pkgversion := range data.Dependencies {
n.Packages = append(n.Packages, NPMPackage{pkgname, pkgversion})
}
for pkgname, pkgversion := range data.DevDependencies {
n.Packages = append(n.Packages, NPMPackage{pkgname, pkgversion})
}
for pkgname := range data.DevDependencies {
n.Packages = append(n.Packages, pkgname)
for pkgname, pkgversion := range data.PeerDependencies {
n.Packages = append(n.Packages, NPMPackage{pkgname, pkgversion})
}
for pkgname := range data.PeerDependencies {
n.Packages = append(n.Packages, pkgname)
for pkgname, pkgversion := range data.OptionalDependencies {
n.Packages = append(n.Packages, NPMPackage{pkgname, pkgversion})
}
for pkgname := range data.OptionalDependencies {
n.Packages = append(n.Packages, pkgname)
for _, pkgname := range data.BundledDependencies {
n.Packages = append(n.Packages, NPMPackage{pkgname, ""})
}
for _, pkgname := range data.BundleDependencies {
n.Packages = append(n.Packages, NPMPackage{pkgname, ""})
}
n.Packages = append(n.Packages, data.BundledDependencies...)
n.Packages = append(n.Packages, data.BundleDependencies...)
return nil
}

Expand All @@ -92,8 +102,19 @@ func (n *NPMLookup) ReadPackagesFromFile(filename string) error {
func (n *NPMLookup) PackagesNotInPublic() []string {
notavail := []string{}
for _, pkg := range n.Packages {
if !n.isAvailableInPublic(pkg, 0) {
notavail = append(notavail, pkg)
if n.localReference(pkg.Version) || n.urlReference(pkg.Version) {
continue
}
if n.gitHubReference(pkg.Version) {
if !n.gitHubOrgExists(pkg.Version) {
notavail = append(notavail, pkg.Name)
continue
} else {
continue
}
}
if !n.isAvailableInPublic(pkg.Name, 0) {
notavail = append(notavail, pkg.Name)
}
}
return notavail
Expand Down Expand Up @@ -138,3 +159,40 @@ func (n *NPMLookup) isAvailableInPublic(pkgname string, retry int) bool {
}
return false
}

// localReference checks if the package version is in fact a reference to filesystem
func (n *NPMLookup) localReference(pkgversion string) bool {
return strings.HasPrefix(strings.ToLower(pkgversion), "file:")
}

// urlReference checks if the package version is in fact a reference to a direct URL
func (n *NPMLookup) urlReference(pkgversion string) bool {
pkgversion = strings.ToLower(pkgversion)
return strings.HasPrefix(pkgversion, "http:") || strings.HasPrefix(pkgversion, "https:")
}

// gitHubReference checks if the package version refers to a GitHub repository
func (n *NPMLookup) gitHubReference(pkgversion string) bool {
return !strings.HasPrefix(pkgversion, "@") && strings.Contains(pkgversion, "/")
}

// gitHubOrgExists returns true if GitHub organization / user exists
func (n NPMLookup) gitHubOrgExists(pkgversion string) bool {
orgName := strings.Split(pkgversion, "/")[0]
if len(orgName) > 0 {
if n.Verbose {
fmt.Print("Checking: https://github.com/" + orgName + " : ")
}
resp, err := http.Get("https://github.com/" + orgName)
if err != nil {
fmt.Printf(" [W] Error while trying to request https://github.com/"+orgName+" : %s\n", err)
return false
}
defer resp.Body.Close()
if n.Verbose {
fmt.Printf("%d\n", resp.StatusCode)
}
return resp.StatusCode == 200
}
return false
}

0 comments on commit ca69ed9

Please sign in to comment.