dl-git-repo-safe 1.0.0
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.
- package/CHANGELOG.md +22 -0
- package/LICENSE +22 -0
- package/README.md +149 -0
- package/index.js +167 -0
- package/package.json +47 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
|
6
|
+
|
|
7
|
+
## [1.0.0] - 2026-04-01
|
|
8
|
+
|
|
9
|
+
### Changed
|
|
10
|
+
- Replaced `git-clone@^0.1.0` with `git-clone-safe@^1.2.0`
|
|
11
|
+
- Updated `require('git-clone')` to `require('git-clone-safe')` in `index.js`
|
|
12
|
+
|
|
13
|
+
### Security
|
|
14
|
+
- **Fixed CVE-2022-25900**: Command injection vulnerability in `git-clone` package.
|
|
15
|
+
The original `git-clone` passes unsanitized arguments to the git binary, allowing
|
|
16
|
+
an attacker to inject arbitrary commands via crafted repository URLs. This fork
|
|
17
|
+
uses `git-clone-safe` which properly sanitizes all git clone arguments.
|
|
18
|
+
|
|
19
|
+
### Note
|
|
20
|
+
- This is a fork of [`download-git-repo@3.0.2`](https://gitlab.com/flippidippi/download-git-repo)
|
|
21
|
+
with the single change of replacing the vulnerable dependency.
|
|
22
|
+
- The API is 100% compatible with the original package — drop-in replacement.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) download-git-repo-safe contributors
|
|
4
|
+
Copyright (c) 2016 flippidippi (original download-git-repo)
|
|
5
|
+
|
|
6
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
7
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
8
|
+
in the Software without restriction, including without limitation the rights
|
|
9
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
10
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
11
|
+
furnished to do so, subject to the following conditions:
|
|
12
|
+
|
|
13
|
+
The above copyright notice and this permission notice shall be included in all
|
|
14
|
+
copies or substantial portions of the Software.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
17
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
18
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
19
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
20
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
21
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
22
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
# download-git-repo-safe
|
|
2
|
+
|
|
3
|
+
> **⚠️ Security Notice**: This is a security-patched fork of [`download-git-repo`](https://gitlab.com/flippidippi/download-git-repo). It replaces the vulnerable `git-clone` dependency with [`git-clone-safe`](https://www.npmjs.com/package/git-clone-safe) to fix **CVE-2022-25900** (command injection via git clone).
|
|
4
|
+
|
|
5
|
+
Download and extract a git repository (GitHub, GitLab, Bitbucket) from node.
|
|
6
|
+
|
|
7
|
+
## What Changed?
|
|
8
|
+
|
|
9
|
+
| | `download-git-repo` (original) | `download-git-repo-safe` (this fork) |
|
|
10
|
+
|---|---|---|
|
|
11
|
+
| `git-clone` | `^0.1.0` (vulnerable) | replaced with `git-clone-safe@^1.2.0` |
|
|
12
|
+
| CVE-2022-25900 | **Affected** | **Fixed** |
|
|
13
|
+
| API | — | **100% compatible** (drop-in replacement) |
|
|
14
|
+
|
|
15
|
+
### CVE-2022-25900
|
|
16
|
+
|
|
17
|
+
The original `download-git-repo` depends on `git-clone@^0.1.0`, which is vulnerable to command injection. An attacker can craft a malicious repository URL that executes arbitrary commands on the system. This fork replaces `git-clone` with `git-clone-safe`, which properly sanitizes git clone arguments.
|
|
18
|
+
|
|
19
|
+
## Migration
|
|
20
|
+
|
|
21
|
+
Replace `download-git-repo` with `download-git-repo-safe`:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
npm uninstall download-git-repo
|
|
25
|
+
npm install download-git-repo-safe
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Or use npm/yarn overrides to replace it transitively:
|
|
29
|
+
|
|
30
|
+
```json
|
|
31
|
+
{
|
|
32
|
+
"overrides": {
|
|
33
|
+
"download-git-repo": "npm:download-git-repo-safe@^1.0.0"
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
No code changes required — the API is identical.
|
|
39
|
+
|
|
40
|
+
## Installation
|
|
41
|
+
|
|
42
|
+
$ npm install download-git-repo-safe
|
|
43
|
+
|
|
44
|
+
## API
|
|
45
|
+
|
|
46
|
+
### download(repository, destination, options, callback)
|
|
47
|
+
|
|
48
|
+
Download a git `repository` to a `destination` folder with `options`, and `callback`.
|
|
49
|
+
|
|
50
|
+
#### repository
|
|
51
|
+
The shorthand repository string to download the repository from:
|
|
52
|
+
|
|
53
|
+
- **GitHub** - `github:owner/name` or simply `owner/name`
|
|
54
|
+
- **GitLab** - `gitlab:owner/name`
|
|
55
|
+
- **Bitbucket** - `bitbucket:owner/name`
|
|
56
|
+
|
|
57
|
+
The `repository` parameter defaults to the `master` branch, but you can specify a branch or tag as a URL fragment like `owner/name#my-branch`.
|
|
58
|
+
In addition to specifying the type of where to download, you can also specify a custom origin like `gitlab:custom.com:owner/name`.
|
|
59
|
+
Custom origin will default to `https` or `git@` for http and clone downloads respectively, unless protocol is specified.
|
|
60
|
+
Feel free to submit an issue or pull request for additional origin options.
|
|
61
|
+
|
|
62
|
+
In addition to having the shorthand for supported git hosts, you can also hit a repository directly with:
|
|
63
|
+
|
|
64
|
+
- **Direct** - `direct:url`
|
|
65
|
+
|
|
66
|
+
This will bypass the shorthand normalizer and pass `url` directly.
|
|
67
|
+
If using `direct` without clone, you must pass the full url to the zip file, including paths to branches if needed.
|
|
68
|
+
If using `direct` with clone, you must pass the full url to the git repo and you can specify a branch like `direct:url#my-branch`.
|
|
69
|
+
|
|
70
|
+
#### destination
|
|
71
|
+
The file path to download the repository to.
|
|
72
|
+
|
|
73
|
+
#### options
|
|
74
|
+
An optional options object parameter with download options. Options include:
|
|
75
|
+
|
|
76
|
+
- `clone` - boolean default `false` - If true use `git clone` instead of an http download. While this can be a bit slower, it does allow private repositories to be used if the appropriate SSH keys are setup.
|
|
77
|
+
- All other options (`proxy`, `headers`, `filter`, etc.) will be passed down accordingly and may override defaults
|
|
78
|
+
- Additional download options: https://github.com/kevva/download#options
|
|
79
|
+
- Additional clone options: https://github.com/jaz303/git-clone#clonerepo-targetpath-options-cb
|
|
80
|
+
|
|
81
|
+
#### callback
|
|
82
|
+
The callback function as `function (err)`.
|
|
83
|
+
|
|
84
|
+
## Examples
|
|
85
|
+
### Shorthand
|
|
86
|
+
Using http download from Github repository at master.
|
|
87
|
+
```javascript
|
|
88
|
+
var download = require('download-git-repo-safe')
|
|
89
|
+
download('flippidippi/download-git-repo-fixture', 'test/tmp', function (err) {
|
|
90
|
+
console.log(err ? 'Error' : 'Success')
|
|
91
|
+
})
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Using git clone from Bitbucket repository at my-branch.
|
|
95
|
+
```javascript
|
|
96
|
+
download('bitbucket:flippidippi/download-git-repo-fixture#my-branch', 'test/tmp', { clone: true }, function (err) {
|
|
97
|
+
console.log(err ? 'Error' : 'Success')
|
|
98
|
+
})
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Using http download from GitLab repository with custom origin and token.
|
|
102
|
+
```javascript
|
|
103
|
+
download('gitlab:mygitlab.com:flippidippi/download-git-repo-fixture#my-branch', 'test/tmp', { headers: { 'PRIVATE-TOKEN': '1234' } }, function (err) {
|
|
104
|
+
console.log(err ? 'Error' : 'Success')
|
|
105
|
+
})
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
Using git clone from GitLab repository with custom origin and protocol.
|
|
109
|
+
Note that the repository type (`github`, `gitlab` etc.) is not required if cloning from a custom origin.
|
|
110
|
+
```javascript
|
|
111
|
+
download('https://mygitlab.com:flippidippi/download-git-repo-fixture#my-branch', 'test/tmp', { clone: true }, function (err) {
|
|
112
|
+
console.log(err ? 'Error' : 'Success')
|
|
113
|
+
})
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### Direct
|
|
117
|
+
Using http download from direct url.
|
|
118
|
+
```javascript
|
|
119
|
+
download('direct:https://gitlab.com/flippidippi/download-git-repo-fixture/repository/archive.zip', 'test/tmp', function (err) {
|
|
120
|
+
console.log(err ? 'Error' : 'Success')
|
|
121
|
+
})
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
Using git clone from direct url at master.
|
|
125
|
+
```javascript
|
|
126
|
+
download('direct:https://gitlab.com/flippidippi/download-git-repo-fixture.git', 'test/tmp', { clone: true }, function (err) {
|
|
127
|
+
console.log(err ? 'Error' : 'Success')
|
|
128
|
+
})
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
Using git clone from direct url at my-branch.
|
|
132
|
+
```javascript
|
|
133
|
+
download('direct:https://gitlab.com/flippidippi/download-git-repo-fixture.git#my-branch', 'test/tmp', { clone: true }, function (err) {
|
|
134
|
+
console.log(err ? 'Error' : 'Success')
|
|
135
|
+
})
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
## Verification
|
|
139
|
+
|
|
140
|
+
To confirm `git-clone-safe` is installed instead of `git-clone`:
|
|
141
|
+
|
|
142
|
+
```bash
|
|
143
|
+
npm ls git-clone git-clone-safe
|
|
144
|
+
npm audit
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
## License
|
|
148
|
+
|
|
149
|
+
MIT
|
package/index.js
ADDED
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
var downloadUrl = require('download')
|
|
2
|
+
var gitclone = require('git-clone-safe')
|
|
3
|
+
var rm = require('rimraf').sync
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Expose `download`.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
module.exports = download
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Download `repo` to `dest` and callback `fn(err)`.
|
|
13
|
+
*
|
|
14
|
+
* @param {String} repo
|
|
15
|
+
* @param {String} dest
|
|
16
|
+
* @param {Object} opts
|
|
17
|
+
* @param {Function} fn
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
function download (repo, dest, opts, fn) {
|
|
21
|
+
if (typeof opts === 'function') {
|
|
22
|
+
fn = opts
|
|
23
|
+
opts = null
|
|
24
|
+
}
|
|
25
|
+
opts = opts || {}
|
|
26
|
+
var clone = opts.clone || false
|
|
27
|
+
delete opts.clone
|
|
28
|
+
|
|
29
|
+
repo = normalize(repo)
|
|
30
|
+
var url = repo.url || getUrl(repo, clone)
|
|
31
|
+
|
|
32
|
+
if (clone) {
|
|
33
|
+
var cloneOptions = {
|
|
34
|
+
checkout: repo.checkout,
|
|
35
|
+
shallow: repo.checkout === 'master',
|
|
36
|
+
...opts
|
|
37
|
+
}
|
|
38
|
+
gitclone(url, dest, cloneOptions, function (err) {
|
|
39
|
+
if (err === undefined) {
|
|
40
|
+
rm(dest + '/.git')
|
|
41
|
+
fn()
|
|
42
|
+
} else {
|
|
43
|
+
fn(err)
|
|
44
|
+
}
|
|
45
|
+
})
|
|
46
|
+
} else {
|
|
47
|
+
var downloadOptions = {
|
|
48
|
+
extract: true,
|
|
49
|
+
strip: 1,
|
|
50
|
+
mode: '666',
|
|
51
|
+
...opts,
|
|
52
|
+
headers: {
|
|
53
|
+
accept: 'application/zip',
|
|
54
|
+
...(opts.headers || {})
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
downloadUrl(url, dest, downloadOptions)
|
|
58
|
+
.then(function (data) {
|
|
59
|
+
fn()
|
|
60
|
+
})
|
|
61
|
+
.catch(function (err) {
|
|
62
|
+
fn(err)
|
|
63
|
+
})
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Normalize a repo string.
|
|
69
|
+
*
|
|
70
|
+
* @param {String} repo
|
|
71
|
+
* @return {Object}
|
|
72
|
+
*/
|
|
73
|
+
|
|
74
|
+
function normalize (repo) {
|
|
75
|
+
var regex = /^(?:(direct):([^#]+)(?:#(.+))?)$/
|
|
76
|
+
var match = regex.exec(repo)
|
|
77
|
+
|
|
78
|
+
if (match) {
|
|
79
|
+
var url = match[2]
|
|
80
|
+
var directCheckout = match[3] || 'master'
|
|
81
|
+
|
|
82
|
+
return {
|
|
83
|
+
type: 'direct',
|
|
84
|
+
url: url,
|
|
85
|
+
checkout: directCheckout
|
|
86
|
+
}
|
|
87
|
+
} else {
|
|
88
|
+
regex = /^(?:(github|gitlab|bitbucket):)?(?:(.+):)?([^/]+)\/([^#]+)(?:#(.+))?$/
|
|
89
|
+
match = regex.exec(repo)
|
|
90
|
+
var type = match[1] || 'github'
|
|
91
|
+
var origin = match[2] || null
|
|
92
|
+
var owner = match[3]
|
|
93
|
+
var name = match[4]
|
|
94
|
+
var checkout = match[5] || 'master'
|
|
95
|
+
|
|
96
|
+
if (origin == null) {
|
|
97
|
+
if (type === 'github') {
|
|
98
|
+
origin = 'github.com'
|
|
99
|
+
} else if (type === 'gitlab') {
|
|
100
|
+
origin = 'gitlab.com'
|
|
101
|
+
} else if (type === 'bitbucket') {
|
|
102
|
+
origin = 'bitbucket.org'
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return {
|
|
107
|
+
type: type,
|
|
108
|
+
origin: origin,
|
|
109
|
+
owner: owner,
|
|
110
|
+
name: name,
|
|
111
|
+
checkout: checkout
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Adds protocol to url in none specified
|
|
118
|
+
*
|
|
119
|
+
* @param {String} url
|
|
120
|
+
* @return {String}
|
|
121
|
+
*/
|
|
122
|
+
|
|
123
|
+
function addProtocol (origin, clone) {
|
|
124
|
+
if (!/^(f|ht)tps?:\/\//i.test(origin)) {
|
|
125
|
+
if (clone) {
|
|
126
|
+
origin = 'git@' + origin
|
|
127
|
+
} else {
|
|
128
|
+
origin = 'https://' + origin
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
return origin
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Return a zip or git url for a given `repo`.
|
|
137
|
+
*
|
|
138
|
+
* @param {Object} repo
|
|
139
|
+
* @return {String}
|
|
140
|
+
*/
|
|
141
|
+
|
|
142
|
+
function getUrl (repo, clone) {
|
|
143
|
+
var url
|
|
144
|
+
|
|
145
|
+
// Get origin with protocol and add trailing slash or colon (for ssh)
|
|
146
|
+
var origin = addProtocol(repo.origin, clone)
|
|
147
|
+
if (/^git@/i.test(origin)) {
|
|
148
|
+
origin = origin + ':'
|
|
149
|
+
} else {
|
|
150
|
+
origin = origin + '/'
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// Build url
|
|
154
|
+
if (clone) {
|
|
155
|
+
url = origin + repo.owner + '/' + repo.name + '.git'
|
|
156
|
+
} else {
|
|
157
|
+
if (repo.type === 'github') {
|
|
158
|
+
url = origin + repo.owner + '/' + repo.name + '/archive/' + repo.checkout + '.zip'
|
|
159
|
+
} else if (repo.type === 'gitlab') {
|
|
160
|
+
url = origin + repo.owner + '/' + repo.name + '/repository/archive.zip?ref=' + repo.checkout
|
|
161
|
+
} else if (repo.type === 'bitbucket') {
|
|
162
|
+
url = origin + repo.owner + '/' + repo.name + '/get/' + repo.checkout + '.zip'
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
return url
|
|
167
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "dl-git-repo-safe",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"license": "MIT",
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "https://github.com/nicolo-ribaudo/download-git-repo-safe.git"
|
|
8
|
+
},
|
|
9
|
+
"description": "Download and extract a git repository (GitHub, GitLab, Bitbucket) from node. Security-patched fork with git-clone-safe.",
|
|
10
|
+
"keywords": [
|
|
11
|
+
"download",
|
|
12
|
+
"github",
|
|
13
|
+
"gitlab",
|
|
14
|
+
"bitbucket",
|
|
15
|
+
"repo",
|
|
16
|
+
"repository",
|
|
17
|
+
"tar",
|
|
18
|
+
"extract",
|
|
19
|
+
"tarball",
|
|
20
|
+
"security",
|
|
21
|
+
"cve-2022-25900",
|
|
22
|
+
"safe"
|
|
23
|
+
],
|
|
24
|
+
"scripts": {
|
|
25
|
+
"test": "mocha",
|
|
26
|
+
"lint": "standard --verbose | snazzy",
|
|
27
|
+
"lint:fix": "standard --verbose --fix | snazzy",
|
|
28
|
+
"precommit": "npm run lint"
|
|
29
|
+
},
|
|
30
|
+
"dependencies": {
|
|
31
|
+
"download": "^7.1.0",
|
|
32
|
+
"git-clone-safe": "^1.2.0",
|
|
33
|
+
"rimraf": "^3.0.0"
|
|
34
|
+
},
|
|
35
|
+
"devDependencies": {
|
|
36
|
+
"fs-readdir-recursive": "^1.1.0",
|
|
37
|
+
"husky": "^3.0.8",
|
|
38
|
+
"mocha": "^6.2.1",
|
|
39
|
+
"snazzy": "^8.0.0",
|
|
40
|
+
"standard": "^14.3.1"
|
|
41
|
+
},
|
|
42
|
+
"standard": {
|
|
43
|
+
"env": [
|
|
44
|
+
"mocha"
|
|
45
|
+
]
|
|
46
|
+
}
|
|
47
|
+
}
|