This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | |||
3 | namespace Hubph\Git; |
||
4 | |||
5 | use Composer\Semver\Semver; |
||
6 | use Psr\Log\LoggerAwareInterface; |
||
7 | use Psr\Log\LoggerAwareTrait; |
||
8 | use Symfony\Component\Filesystem\Filesystem; |
||
9 | use Hubph\Util\ExecWithRedactionTrait; |
||
10 | |||
11 | class Remote implements LoggerAwareInterface |
||
12 | { |
||
13 | use ExecWithRedactionTrait; |
||
14 | use LoggerAwareTrait; |
||
15 | |||
16 | protected $remote; |
||
17 | |||
18 | public function __construct($remote) |
||
19 | { |
||
20 | $this->remote = $remote; |
||
21 | } |
||
22 | |||
23 | public static function create($remote, $api = null) |
||
24 | { |
||
25 | $remote = new self($remote); |
||
26 | $remote->addAuthentication($api); |
||
27 | return $remote; |
||
28 | } |
||
29 | |||
30 | public static function fromDir($dir, $remote = 'origin') |
||
31 | { |
||
32 | $currentURL = exec("git -C {$dir} config --get remote.{$remote}.url"); |
||
33 | return new self($currentURL); |
||
34 | } |
||
35 | |||
36 | public function addAuthentication($api = null) |
||
37 | { |
||
38 | if ($api) { |
||
39 | $this->remote = $api->addTokenAuthentication($this->remote); |
||
40 | } |
||
41 | } |
||
42 | |||
43 | public function valid() |
||
44 | { |
||
45 | return !empty($this->remote); |
||
46 | } |
||
47 | |||
48 | public function projectWithOrg() |
||
49 | { |
||
50 | return static::projectWithOrgFromUrl($this->remote); |
||
51 | } |
||
52 | |||
53 | // https://{$token}:[email protected]/{$projectWithOrg}.git"; |
||
54 | // [email protected]:{$projectWithOrg}.git |
||
55 | View Code Duplication | public static function projectWithOrgFromUrl($remote) |
|
0 ignored issues
–
show
|
|||
56 | { |
||
57 | $remote = preg_replace('#^git@[^:]*:#', '', $remote); |
||
58 | $remote = preg_replace('#^[^:]*://[^/]*/#', '', $remote); |
||
59 | $remote = preg_replace('#\.git$#', '', $remote); |
||
60 | |||
61 | return $remote; |
||
62 | } |
||
63 | |||
64 | public function url() |
||
65 | { |
||
66 | return $this->remote; |
||
67 | } |
||
68 | |||
69 | public function org() |
||
70 | { |
||
71 | $projectWithOrg = $this->projectWithOrg(); |
||
72 | $parts = explode('/', $projectWithOrg); |
||
73 | return $parts[0]; |
||
74 | } |
||
75 | |||
76 | public function project() |
||
77 | { |
||
78 | $projectWithOrg = $this->projectWithOrg(); |
||
79 | $parts = explode('/', $projectWithOrg); |
||
80 | return $parts[1]; |
||
81 | } |
||
82 | |||
83 | public function host() |
||
84 | { |
||
85 | if (preg_match('#@([^:/]+)[:/]', $this->remote, $matches)) { |
||
86 | return $matches[1]; |
||
87 | } |
||
88 | return false; |
||
89 | } |
||
90 | |||
91 | /** |
||
92 | * Return an associative array of tag names -> sha |
||
93 | * |
||
94 | * @return array |
||
95 | */ |
||
96 | public function tags($constraint_arg, $stable = true, $tag_prefix = '') |
||
97 | { |
||
98 | $filter = $this->appearsToBeSemver($constraint_arg) ? '' : $constraint_arg; |
||
99 | $version_constraints = $this->appearsToBeSemver($constraint_arg) ? $constraint_arg : '*'; |
||
100 | $trailing = $stable ? '[0-9.]*' : '.*'; |
||
101 | $tags = $this->git('ls-remote --tags --refs {remote}', ['remote' => $this->remote]); |
||
102 | $regex = "#([^ ]+)[ \t]+refs/tags/$tag_prefix($filter$trailing\$)#"; |
||
103 | $result = []; |
||
104 | foreach ($tags as $tagLine) { |
||
0 ignored issues
–
show
The expression
$tags of type null|array is not guaranteed to be traversable. How about adding an additional type check?
There are different options of fixing this problem.
![]() |
|||
105 | if (preg_match($regex, $tagLine, $matches)) { |
||
106 | $sha = $matches[1]; |
||
107 | $tag = $matches[2]; |
||
108 | if ($this->satisfies($tag, $version_constraints)) { |
||
109 | $result[$tag] = ['ref' => $sha]; |
||
110 | } |
||
111 | } |
||
112 | } |
||
113 | // Sort result by keys using natural order |
||
114 | uksort($result, "strnatcmp"); |
||
115 | return $result; |
||
116 | } |
||
117 | |||
118 | /** |
||
119 | * Delete a tag from the remote |
||
120 | */ |
||
121 | public function delete($tag) |
||
122 | { |
||
123 | $this->git('push --delete {remote} {tag}', ['remote' => $this->remote, 'tag' => $tag]); |
||
124 | } |
||
125 | |||
126 | protected function satisfies($tag, $version_constraints) |
||
127 | { |
||
128 | // If we are using a regex rather than semver, then pass anything. |
||
129 | if ($version_constraints == '*') { |
||
130 | return true; |
||
131 | } |
||
132 | |||
133 | try { |
||
134 | return Semver::satisfies($tag, $version_constraints); |
||
135 | } catch (\Exception $e) { |
||
136 | return false; |
||
137 | } |
||
138 | } |
||
139 | |||
140 | // @deprecated: we should just use semver everywhere, not regex. |
||
141 | // The downside to this theory is that WordPress doesn't use semver. |
||
142 | protected function appearsToBeSemver($arg) |
||
143 | { |
||
144 | return ($arg[0] == '^') || ($arg[0] == '~'); |
||
145 | } |
||
146 | |||
147 | public function releases($majorVersion /*= '[0-9]+'*/, $stable, $tag_prefix) |
||
148 | { |
||
149 | return $this->tags("$majorVersion\.", $stable, $tag_prefix); |
||
150 | } |
||
151 | |||
152 | /** |
||
153 | * Return the latest release in the specified major version series |
||
154 | * |
||
155 | * TODO: allow for beta or RC builds (by request via a second parameter) |
||
156 | */ |
||
157 | public function latest($majorVersion /*= '[0-9]+'*/, $stable, $tag_prefix) |
||
158 | { |
||
159 | $tags = $this->releases($majorVersion, $stable, $tag_prefix); |
||
160 | $tags = array_keys($tags); |
||
161 | return array_pop($tags); |
||
162 | } |
||
163 | |||
164 | /** |
||
165 | * Return 'true' if the provided tag exists on this remote. |
||
166 | */ |
||
167 | public function has($tag_to_check, $majorVersion = '[0-9]+', $stable = false, $tag_prefix = '') |
||
168 | { |
||
169 | $tags = $this->releases($majorVersion, $stable, $tag_prefix); |
||
170 | return array_key_exists($tag_to_check, $tags); |
||
171 | } |
||
172 | |||
173 | /** |
||
174 | * Return a sanitized version of this remote (sans authentication string) |
||
175 | */ |
||
176 | public function __toString() |
||
177 | { |
||
178 | $host = $this->host(); |
||
179 | $projectWithOrg = $this->projectWithOrg(); |
||
180 | |||
181 | return "git@{$host}:{$projectWithOrg}.git"; |
||
182 | } |
||
183 | |||
184 | /** |
||
185 | * Run a git function on the local working copy. Fail on error. |
||
186 | * |
||
187 | * @return string stdout |
||
188 | */ |
||
189 | public function git($cmd, $replacements = [], $redacted = []) |
||
190 | { |
||
191 | return $this->execWithRedaction('git ' . $cmd, $replacements, $redacted); |
||
192 | } |
||
193 | } |
||
194 |
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.