Issues (6)

Security Analysis    no request data  

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

src/DirectAdmin/Objects/Domain.php (2 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
/*
4
 * DirectAdmin API Client
5
 * (c) Omines Internetbureau B.V. - https://omines.nl/
6
 *
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 */
10
11
namespace Omines\DirectAdmin\Objects;
12
13
use Omines\DirectAdmin\Context\UserContext;
14
use Omines\DirectAdmin\DirectAdminException;
15
use Omines\DirectAdmin\Objects\Domains\Subdomain;
16
use Omines\DirectAdmin\Objects\Email\Forwarder;
17
use Omines\DirectAdmin\Objects\Email\Mailbox;
18
use Omines\DirectAdmin\Objects\Users\User;
19
use Omines\DirectAdmin\Utility\Conversion;
20
21
/**
22
 * Encapsulates a domain and its derived objects, like aliases, pointers and mailboxes.
23
 *
24
 * @author Niels Keurentjes <[email protected]>
25
 */
26
class Domain extends BaseObject
27
{
28
    const CACHE_FORWARDERS = 'forwarders';
29
    const CACHE_MAILBOXES = 'mailboxes';
30
    const CACHE_SUBDOMAINS = 'subdomains';
31
32
    const CATCHALL_BLACKHOLE = ':blackhole:';
33
    const CATCHALL_FAIL = ':fail:';
34
35
    /** @var string */
36
    private $domainName;
37
38
    /** @var User */
39
    private $owner;
40
41
    /** @var string[] */
42
    private $aliases;
43
44
    /** @var string[] */
45
    private $pointers;
46
47
    /** @var float */
48
    private $bandwidthUsed;
49
50
    /** @var float|null */
51
    private $bandwidthLimit;
52
53
    /** @var float */
54
    private $diskUsage;
55
56
    /**
57
     * Construct the object.
58
     *
59
     * @param string $name The domain name
60
     * @param UserContext $context The owning user context
61
     * @param string|array $config The basic config string as returned by CMD_API_ADDITIONAL_DOMAINS
62
     */
63
    public function __construct($name, UserContext $context, $config)
64
    {
65
        parent::__construct($name, $context);
66
        $this->setConfig($context, is_array($config) ? $config : \GuzzleHttp\Psr7\parse_query($config));
67
    }
68
69
    /**
70
     * Creates a new domain under the specified user.
71
     *
72
     * @param User $user Owner of the domain
73
     * @param string $domainName Domain name to create
74
     * @param float|null $bandwidthLimit Bandwidth limit in MB, or NULL to share with account
75
     * @param float|null $diskLimit Disk limit in MB, or NULL to share with account
76
     * @param bool|null $ssl Whether SSL is to be enabled, or NULL to fallback to account default
77
     * @param bool|null $php Whether PHP is to be enabled, or NULL to fallback to account default
78
     * @param bool|null $cgi Whether CGI is to be enabled, or NULL to fallback to account default
79
     * @return Domain The newly created domain
80
     */
81
    public static function create(User $user, $domainName, $bandwidthLimit = null, $diskLimit = null, $ssl = null, $php = null, $cgi = null)
82
    {
83
        $options = [
84
            'action' => 'create',
85
            'domain' => $domainName,
86
            (isset($bandwidthLimit) ? 'bandwidth' : 'ubandwidth') => $bandwidthLimit,
87
            (isset($diskLimit) ? 'quota' : 'uquota') => $diskLimit,
88
            'ssl' => Conversion::onOff($ssl, $user->hasSSL()),
89
            'php' => Conversion::onOff($php, $user->hasPHP()),
90
            'cgi' => Conversion::onOff($cgi, $user->hasCGI()),
91
        ];
92
        $user->getContext()->invokeApiPost('DOMAIN', $options);
93
        $config = $user->getContext()->invokeApiGet('ADDITIONAL_DOMAINS');
94
        return new self($domainName, $user->getContext(), $config[$domainName]);
95
    }
96
97
    /**
98
     * Creates a new email forwarder.
99
     *
100
     * @param string $prefix Part of the email address before the @
101
     * @param string|string[] $recipients One or more recipients
102
     * @return Forwarder The newly created forwarder
103
     */
104
    public function createForwarder($prefix, $recipients)
105
    {
106
        return Forwarder::create($this, $prefix, $recipients);
107
    }
108
109
    /**
110
     * Creates a new mailbox.
111
     *
112
     * @param string $prefix Prefix for the account
113
     * @param string $password Password for the account
114
     * @param int|null $quota Quota in megabytes, or zero/null for unlimited
115
     * @param int|null $sendLimit Send limit, or 0 for unlimited, or null for system default
116
     * @return Mailbox The newly created mailbox
117
     */
118
    public function createMailbox($prefix, $password, $quota = null, $sendLimit = null)
119
    {
120
        return Mailbox::create($this, $prefix, $password, $quota, $sendLimit);
121
    }
122
123
    /**
124
     * Creates a pointer or alias.
125
     *
126
     * @param string $domain
127
     * @param bool $alias
128
     */
129
    public function createPointer($domain, $alias = false)
130
    {
131
        $parameters = [
132
            'domain' => $this->domainName,
133
            'from' => $domain,
134
            'action' => 'add',
135
        ];
136
        if ($alias) {
137
            $parameters['alias'] = 'yes';
138
            $list = &$this->aliases;
139
        } else {
140
            $list = &$this->pointers;
141
        }
142
        $this->getContext()->invokeApiPost('DOMAIN_POINTER', $parameters);
143
        $list[] = $domain;
144
        $list = array_unique($list);
145
    }
146
147
    /**
148
     * Creates a new subdomain.
149
     *
150
     * @param string $prefix Prefix to add before the domain name
151
     * @return Subdomain The newly created subdomain
152
     */
153
    public function createSubdomain($prefix)
154
    {
155
        return Subdomain::create($this, $prefix);
156
    }
157
158
    /**
159
     * Deletes this domain from the user.
160
     */
161
    public function delete()
162
    {
163
        $this->getContext()->invokeApiPost('DOMAIN', [
164
            'delete' => true,
165
            'confirmed' => true,
166
            'select0' => $this->domainName,
167
        ]);
168
        $this->owner->clearCache();
169
    }
170
171
    /**
172
     * @return string[] List of aliases for this domain
173
     */
174
    public function getAliases()
175
    {
176
        return $this->aliases;
177
    }
178
179
    /**
180
     * @return float Bandwidth used in megabytes
181
     */
182
    public function getBandwidthUsed()
183
    {
184
        return $this->bandwidthUsed;
185
    }
186
187
    /**
188
     * @return float|null Bandwidth quotum in megabytes, or NULL for unlimited
189
     */
190
    public function getBandwidthLimit()
191
    {
192
        return $this->bandwidthLimit;
193
    }
194
195
    /**
196
     * @return string|null Currently configured catch-all configuration
197
     */
198
    public function getCatchall()
199
    {
200
        $value = $this->getContext()->invokeApiGet('EMAIL_CATCH_ALL', ['domain' => $this->domainName]);
201
        return isset($value['value']) ? $value['value'] : null;
202
    }
203
204
    /**
205
     * @return float Disk usage in megabytes
206
     */
207
    public function getDiskUsage()
208
    {
209
        return $this->diskUsage;
210
    }
211
212
    /**
213
     * @return string The real domain name
214
     */
215
    public function getDomainName()
216
    {
217
        return $this->domainName;
218
    }
219
220
    /**
221
     * Returns unified sorted list of main domain name, aliases and pointers.
222
     *
223
     * @return string[]
224
     */
225
    public function getDomainNames()
226
    {
227
        return $this->getCache('domainNames', function () {
228
            $list = array_merge($this->aliases, $this->pointers, [$this->getDomainName()]);
229
            sort($list);
230
            return $list;
231
        });
232
    }
233
234
    /**
235
     * @return Forwarder[] Associative array of forwarders
236
     */
237 View Code Duplication
    public function getForwarders()
0 ignored issues
show
This method seems to be duplicated in your project.

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.

Loading history...
238
    {
239
        return $this->getCache(self::CACHE_FORWARDERS, function () {
240
            $forwarders = $this->getContext()->invokeApiGet('EMAIL_FORWARDERS', [
241
                'domain' => $this->getDomainName(),
242
            ]);
243
            return DomainObject::toDomainObjectArray($forwarders, Forwarder::class, $this);
244
        });
245
    }
246
247
    /**
248
     * @return Mailbox[] Associative array of mailboxes
249
     */
250 View Code Duplication
    public function getMailboxes()
0 ignored issues
show
This method seems to be duplicated in your project.

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.

Loading history...
251
    {
252
        return $this->getCache(self::CACHE_MAILBOXES, function () {
253
            $boxes = $this->getContext()->invokeApiGet('POP', [
254
                'domain' => $this->getDomainName(),
255
                'action' => 'full_list',
256
            ]);
257
            return DomainObject::toDomainObjectArray($boxes, Mailbox::class, $this);
258
        });
259
    }
260
261
    /**
262
     * @return User
263
     */
264
    public function getOwner()
265
    {
266
        return $this->owner;
267
    }
268
269
    /**
270
     * @return string[] List of domain pointers for this domain
271
     */
272
    public function getPointers()
273
    {
274
        return $this->pointers;
275
    }
276
277
    /**
278
     * @return Subdomain[] Associative array of subdomains
279
     */
280
    public function getSubdomains()
281
    {
282
        return $this->getCache(self::CACHE_SUBDOMAINS, function () {
283
            $subs = $this->getContext()->invokeApiGet('SUBDOMAINS', ['domain' => $this->getDomainName()]);
284
            $subs = array_combine($subs, $subs);
285
            return DomainObject::toDomainObjectArray($subs, Subdomain::class, $this);
286
        });
287
    }
288
289
    /**
290
     * Invokes a POST command on a domain object.
291
     *
292
     * @param string $command Command to invoke
293
     * @param string $action Action to execute
294
     * @param array $parameters Additional options for the command
295
     * @param bool $clearCache Whether to clear the domain cache on success
296
     * @return array Response from the API
297
     */
298
    public function invokePost($command, $action, $parameters = [], $clearCache = true)
299
    {
300
        $response = $this->getContext()->invokeApiPost($command, array_merge([
301
            'action' => $action,
302
            'domain' => $this->domainName,
303
        ], $parameters));
304
        if ($clearCache) {
305
            $this->clearCache();
306
        }
307
        return $response;
308
    }
309
310
    /**
311
     * @param string $newValue New address for the catch-all, or one of the CATCHALL_ constants
312
     */
313
    public function setCatchall($newValue)
314
    {
315
        $parameters = array_merge(['domain' => $this->domainName, 'update' => 'Update'],
316
            (empty($newValue) || $newValue[0] == ':') ? ['catch' => $newValue] : ['catch' => 'address', 'value' => $newValue]);
317
        $this->getContext()->invokeApiPost('EMAIL_CATCH_ALL', $parameters);
318
    }
319
320
    /**
321
     * Allows Domain object to be passed as a string with its domain name.
322
     *
323
     * @return string
324
     */
325
    public function __toString()
326
    {
327
        return $this->getDomainName();
328
    }
329
330
    /**
331
     * Sets configuration options from raw DirectAdmin data.
332
     *
333
     * @param UserContext $context Owning user context
334
     * @param array $config An array of settings
335
     */
336
    private function setConfig(UserContext $context, array $config)
337
    {
338
        $this->domainName = $config['domain'];
339
340
        // Determine owner
341
        if ($config['username'] === $context->getUsername()) {
342
            $this->owner = $context->getContextUser();
343
        } else {
344
            throw new DirectAdminException('Could not determine relationship between context user and domain');
345
        }
346
347
        // Parse plain options
348
        $bandwidths = array_map('trim', explode('/', $config['bandwidth']));
349
        $this->bandwidthUsed = floatval($bandwidths[0]);
350
        $this->bandwidthLimit = !isset($bandwidths[1]) || ctype_alpha($bandwidths[1]) ? null : floatval($bandwidths[1]);
351
        $this->diskUsage = floatval($config['quota']);
352
353
        $this->aliases = array_filter(explode('|', $config['alias_pointers']));
354
        $this->pointers = array_filter(explode('|', $config['pointers']));
355
    }
356
}
357