Issues (111)

Security Analysis    not enabled

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.

app/Settings.php (5 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
 * Copyright (C) 2016 Tony Murray <[email protected]>
4
 * This program is free software: you can redistribute it and/or modify
5
 * it under the terms of the GNU General Public License as published by
6
 * the Free Software Foundation, either version 3 of the License, or
7
 * (at your option) any later version.
8
 *
9
 * This program is distributed in the hope that it will be useful,
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
12
 * GNU General Public License for more details.
13
 *
14
 * You should have received a copy of the GNU General Public License
15
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
16
 */
17
/**
18
 * Settings.php
19
 *
20
 * @package    LibreNMS
21
 * @author     Tony Murray <[email protected]>
22
 * @copyright  2016 Tony Murray
23
 * @license    @license http://opensource.org/licenses/GPL-3.0 GNU Public License v3 or later
24
 */
25
namespace App;
26
27
use App\Models\DbConfig;
28
use Cache;
29
use Config;
30
use Illuminate\Contracts\Config\Repository as ConfigContract;
31
32
// adds the possibility to replace the default Config facade
33
34
class Settings implements ConfigContract
35
{
36
    /**
37
     * The tag for the cache.
38
     *
39
     * @var string
40
     */
41
    public static $cache_tag = "Settings";
42
    /**
43
     * The amount of time in minutes to store values in cache
44
     *
45
     * @var int
46
     */
47
    private $cache_time;
48
49
    /**
50
     * Settings constructor.
51
     */
52 66
    public function __construct()
53
    {
54 66
        $this->cache_time = env('CACHE_LIFETIME', 60);
55 66
    }
56
57
    /**
58
     * Set a key value pair into the Settings store.
59
     *
60
     * @param string $key A . separated path to this setting
61
     * @param array|null $value A value or an array. If value is an array it will be converted to a . separate path(s) concatinated onto the given key
62
     * @throws \Exception
63
     */
64 33
    public function set($key, $value = null)
65
    {
66 33
        if (is_array($value)) {
67
            // repeat until value contains no arrays
68 14
            foreach ($value as $k => $v) {
69 14
                if (!empty($key)) {
70 13
                    if (is_string($k) && !str_contains($k, '.') && DbConfig::exactKey($key)->exists() && DbConfig::key($key)->count() == 1) {
0 ignored issues
show
The method exists does only exist in Illuminate\Database\Query\Builder, but not in App\Models\DbConfig.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
The method count does only exist in Illuminate\Database\Query\Builder, but not in App\Models\DbConfig.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
71
                        // check that we aren't trying to set an array onto an existing value only setting
72 1
                        throw new \Exception("Attempting to set array value to existing non-array value at the key '".$key."'");
73
                    } else {
74
                        // we are not at the leaf yet, add this chunk to the key and recurse
75 12
                        $this->set($key.'.'.$k, $v);
76
                    }
77
                } else {
78
                    // a leaf, recurse one last time
79 13
                    $this->set($k, $v);
80
                }
81
            }
82
        } else {
83
            // make sure we can save this
84 33
            if ($this->isReadOnly($key)) {
85 1
                throw new \Exception("The setting '".$key."' is read only");
86
            }
87
88
            // flush the cache and save the value in db and cache
89 32
            $this->flush($key);
90 32
            DbConfig::updateOrCreate(['config_name' => $key], ['config_value' => $value]);
91 32
            Cache::tags(self::$cache_tag)->put($key, $value, $this->cache_time);
92
        }
93 32
    }
94
95
    /**
96
     * Get a value from the Settings store.
97
     *
98
     * @param string $key A full or partial . separated key.
99
     * @param null $default If the key isn't found, return this value. By default undefined keys return null.
100
     * @return mixed If the $key is a full path, a bare value will be returned.  If it is a partial path, a nested array will be retuned.
101
     */
102
    public function get($key, $default = null, $is_array = false)
103
    {
104
        // return value from cache or fetch it and return it
105 60
        return Cache::tags(self::$cache_tag)->remember($key, $this->cache_time, function () use ($key, $default, $is_array) {
106
            // fetch the values from storage
107 52
            if (Config::has('config.'.$key)) {
108 5
                $config_data = Config::get('config.'.$key, $default);
109
            }
110 52
            $db_data = DbConfig::key($key)->get(['config_name', 'config_value']);
0 ignored issues
show
The method get does only exist in Illuminate\Database\Query\Builder, but not in App\Models\DbConfig.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
111
112 52
            if (count($db_data) == 1 && $db_data->first()->config_name == $key && $is_array !== true) {
113
                // return a value if we are getting one item and it is the requested item (not recursing)
114 6
                return $db_data->first()->config_value;
115 49
            } elseif (count($db_data) >= 1) {
116
                // convert the collection to an array
117 14
                $result = self::collectionToArray($db_data, $key);
118
119
                // if we have config_data, merge them
120 14
                if (isset($config_data)) {
121 2
                    return array_replace_recursive($config_data, $result);
122
                } else {
123 12
                    return $result;
124
                }
125
            }
126
127
            // fall back to config.php/defaults.php
128 37
            if (isset($config_data) && (!is_array($config_data) || count($db_data) == 0)) {
129
                // return the value from config.php if it is a value
130 2
                return $config_data;
131
            }
132
133
134
            // we couldn't find the key, return the default
135 35
            return $default;
136 60
        });
137
    }
138
139
    /**
140
     * Convert an Eloquent Collection into a nested array
141
     *
142
     * @param $data \Illuminate\Database\Eloquent\Collection The Collection.
143
     * @param string $prefix Path to prepend. Do not include trailing .
144
     * @return array The resulting nested array.
145
     */
146 15
    private static function collectionToArray($data, $prefix = "")
147
    {
148 15
        $tree = array();
149 15
        foreach ($data as $item) {
150 15
            $key = $item->config_name;
151 15
            if (starts_with($key, $prefix)) {
152 14
                $key = substr($key, strlen($prefix));
153
            }
154 15
            $parts = explode('.', trim($key, '.'));
155
156 15
            $temp = &$tree;
157 15
            foreach ($parts as $part) {
158 15
                $temp = &$temp[$part];
159
            }
160 15
            $temp = $item->config_value;
161 15
            unset($temp);
162
        }
163 15
        return $tree;
164
    }
165
166
    /**
167
     * Check if the key is defined in the Settings store.
168
     *
169
     * @param string $key Only full paths will return true.
170
     * @return bool
171
     */
172 2
    public function has($key)
173
    {
174 2
        return (Cache::tags(self::$cache_tag)->has($key) || Config::has('config.'.$key) || DbConfig::key($key)->exists());
0 ignored issues
show
The method exists does only exist in Illuminate\Database\Query\Builder, but not in App\Models\DbConfig.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
175
    }
176
177
    /**
178
     * Check if the key is read only.
179
     * When the user is not a global admin.
180
     * Currently, $key is unused
181
     *
182
     * @param string $key The path to check
183
     * @return boolean false or the source: config | auth
184
     */
185 34
    public function isReadOnly($key)
186
    {
187 34
        $user = \Auth::user();
188 34
        return (is_null($user) || !$user->isAdmin());
189
    }
190
191
    /**
192
     * Forget a key and all children
193
     * This cannot forget variables set in config.php
194
     *
195
     * @param string $key Explicit key to forget
196
     */
197 3
    public function forget($key)
198
    {
199
        // Cannot remove from config
200
201 3
        $count = DbConfig::key($key)->count();
0 ignored issues
show
The method count does only exist in Illuminate\Database\Query\Builder, but not in App\Models\DbConfig.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
202 3
        if ($count == 1) {
203 2
            $this->flush($key);
204
        } else {
205 3
            $this->flush(); // possible optimization: selective flush
206
        }
207
208 3
        DbConfig::key($key)->delete();
209 3
    }
210
211
    /**
212
     * Get all settings defined in the Settings store.
213
     *
214
     * @return array A nested array of all settings.
215
     */
216 1
    public function all()
217
    {
218
        // no caching :(
219 1
        $config_settings = Config::all()['config'];
220 1
        $db_settings = self::collectionToArray(DbConfig::all());
221 1
        return array_replace_recursive($config_settings, $db_settings);
222
    }
223
224
    // ---- Local Utility functions ----
225
226
    /**
227
     * Clear the settings cache.
228
     * If path is set, only clear the path and it's parents.
229
     * This will not clear children.
230
     *
231
     * @param string $key The path to clear.
232
     */
233 35
    public function flush($key = null)
234
    {
235 35
        if (is_null($key)) {
236
            // Clear all cache
237 12
            Cache::tags(self::$cache_tag)->flush();
238
        } else {
239
            // Clear specific path
240 32
            $path = [];
241 32
            foreach (explode('.', $key) as $element) {
242 32
                $path[] = $element;
243 32
                Cache::tags(self::$cache_tag)->forget(join('.', $path));
244
            }
245
        }
246 35
    }
247
248
    /**
249
     * Prepend a value onto an array configuration value.
250
     *
251
     * @param  string $key
252
     * @param  mixed $value
253
     * @return void
254
     */
255 1
    public function prepend($key, $value)
256
    {
257 1
        $var = $this->get($key);
258
259 1
        if (is_array($var)) {
260 1
            $this->forget($key);
261 1
            array_unshift($var, $value);
262 1
            $this->set($key, $var);
263
        } else {
264 1
            $arr = [$value];
265 1
            if (!is_null($var)) {
266 1
                $arr[] = $var;
267
            }
268
269 1
            $this->forget($key);
270 1
            $this->set($key, $arr);
271
        }
272 1
    }
273
274
    /**
275
     * Push a value onto an array configuration value.
276
     *
277
     * @param  string $key
278
     * @param  mixed $value
279
     * @return void
280
     */
281 1
    public function push($key, $value)
282
    {
283 1
        $var = $this->get($key);
284 1
        if (is_array($var)) {
285 1
            $var[] = $value;
286 1
            $this->set($key, $var);
287
        } else {
288 1
            $arr = array();
289 1
            if (!is_null($var)) {
290 1
                $arr[] = $var;
291
            }
292 1
            $arr[] = $value;
293
294 1
            $this->forget($key);
295 1
            $this->set($key, $arr);
296
        }
297 1
    }
298
}
299