Move API routing to Laravel (#10457)

* Add more api helper functions
to centralize code more

* Enable cors

* Initial Legacy route in Laravel

* Force api v0 responses to json
Add a couple more routes

* more paths, pretty print the json response
pass parameters to the api function

* devices basic functions

* Port generic graph function
check permissions function accepts callback to avoid lots of if statements

* move vlans

* links

* graphs

* fdb

* health

* wireless

* port graphs

* ip functions
split em up

* port_stack

* components

* compoment add/edit/delete

* get_device_groups

* port stats

* port graphs

* get_devices_by_group

* port_groups

* api_get_graph

* show_endpoints

* get_bill

* get_bill_graph

* get_bill_graphdata

* get_bill_history

* get_bill_history_graph

* remaining bill functions

* list_alerts

* ack/unmute alert

* Some cleanups

* Some cleanups

* list_alert_rules

* alert rule add/edit/delete

* inventory

* list_cbgp

* vrf

* list_ipsec

* list_fdb

* list_links (fix both usages)

* list_locations

* list_locations

* list_vlans

* list_ip_addresses

* list_arp

* list_ip_networks

* cleanup

* services

* list_logs and fix authlog.......

* cleanup

* cleanup 2

* remove slim

* don't load schema more than once

* basic test

* fix style

* downgrade laravel-cors to a version that supports PHP 7.1
This commit is contained in:
Tony Murray
2019-07-29 16:32:37 -05:00
committed by GitHub
parent f62f254465
commit 89fae9be1d
19 changed files with 1396 additions and 1487 deletions

View File

@ -0,0 +1,45 @@
<?php
/**
* LegacyApiController.php
*
* -Description-
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @package LibreNMS
* @link http://librenms.org
* @copyright 2019 Tony Murray
* @author Tony Murray <murraytony@gmail.com>
*/
namespace App\Api\Controllers;
class LegacyApiController
{
/**
* Pass through api functions to api_functions.inc.php
*
* @param string $method_name
* @param array $arguments
* @return mixed
*/
public function __call($method_name, $arguments)
{
$init_modules = ['web', 'alerts'];
require base_path('/includes/init.php');
require_once base_path('includes/html/api_functions.inc.php');
return app()->call($method_name, $arguments);
}
}

View File

@ -64,18 +64,4 @@ class Handler extends ExceptionHandler
return parent::convertExceptionToArray($e); return parent::convertExceptionToArray($e);
} }
/**
* Convert an authentication exception into an unauthenticated response.
*
* @param \Illuminate\Http\Request $request
* @param \Illuminate\Auth\AuthenticationException $exception
* @return \Illuminate\Http\Response
*/
protected function unauthenticated($request, AuthenticationException $exception)
{
return $request->expectsJson() || $request->is('api/*')
? response()->json(['message' => $exception->getMessage()], 401)
: redirect()->guest($exception->redirectTo() ?? route('login'));
}
} }

View File

@ -78,9 +78,4 @@ class LegacyController extends Controller
'refresh' => $no_refresh ? 0 : Config::get('page_refresh'), 'refresh' => $no_refresh ? 0 : Config::get('page_refresh'),
]); ]);
} }
public function api($path = '')
{
include base_path('includes/html/legacy_api_v0.php');
}
} }

View File

@ -49,7 +49,8 @@ class Kernel extends HttpKernel
'api' => [ 'api' => [
'bindings', 'bindings',
'auth:token' 'auth:token',
\Spatie\Cors\Cors::class,
], ],
]; ];

View File

@ -0,0 +1,77 @@
<?php
/**
* CorsApiProfile.php
*
* -Description-
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @package LibreNMS
* @link http://librenms.org
* @copyright 2019 Tony Murray
* @author Tony Murray <murraytony@gmail.com>
*/
namespace App\Http\Profile;
use Illuminate\Support\Arr;
use LibreNMS\Config;
use Spatie\Cors\CorsProfile\DefaultProfile;
class CorsApiProfile extends DefaultProfile
{
public function addCorsHeaders($response)
{
return Config::get('api.cors.enabled') ?
parent::addCorsHeaders($response) :
$response;
}
public function addPreflightHeaders($response)
{
return Config::get('api.cors.enabled') ?
parent::addPreflightHeaders($response) :
$response;
}
public function allowHeaders(): array
{
return Arr::wrap(Config::get('api.cors.allowheaders', []));
}
public function allowMethods(): array
{
return Arr::wrap(Config::get('api.cors.allowmethods', []));
}
public function maxAge(): int
{
return (int)Config::get('api.cors.maxage', 86400);
}
public function allowOrigins(): array
{
return Arr::wrap(Config::get('api.cors.origin', []));
}
public function exposeHeaders(): array
{
return Arr::wrap(Config::get('api.cors.exposeheaders', []));
}
public function allowCredentials(): bool
{
return (bool)Config::get('api.cors.allowcredentials');
}
}

View File

@ -25,6 +25,8 @@
namespace App\Models; namespace App\Models;
use Illuminate\Support\Str;
class ApiToken extends BaseModel class ApiToken extends BaseModel
{ {
public $timestamps = false; public $timestamps = false;
@ -60,6 +62,18 @@ class ApiToken extends BaseModel
return User::find(self::idFromToken($token)); return User::find(self::idFromToken($token));
} }
public static function generateToken(User $user, $description = '')
{
$token = new static;
$token->user_id = $user->user_id;
$token->token_hash = $bytes = bin2hex(random_bytes(16));
$token->description = $description;
$token->disabled = false;
$token->save();
return $token;
}
/** /**
* Get the user_id for the given token. * Get the user_id for the given token.
* *

View File

@ -160,6 +160,11 @@ class User extends Authenticatable
// ---- Define Relationships ---- // ---- Define Relationships ----
public function apiToken()
{
return $this->hasOne('App\Models\ApiToken', 'user_id', 'user_id');
}
public function devices() public function devices()
{ {
if ($this->hasGlobalRead()) { if ($this->hasGlobalRead()) {

View File

@ -21,35 +21,34 @@
], ],
"require": { "require": {
"php": "^7.1.3", "php": "^7.1.3",
"ext-pdo": "*",
"ext-pcre": "*",
"ext-curl": "*", "ext-curl": "*",
"ext-session": "*",
"ext-xml": "*",
"ext-gd": "*", "ext-gd": "*",
"ext-json": "*", "ext-json": "*",
"ext-mbstring": "*", "ext-mbstring": "*",
"laravel/laravel": "5.7.*", "ext-pcre": "*",
"ezyang/htmlpurifier": "^4.8", "ext-pdo": "*",
"phpmailer/phpmailer": "~6.0", "ext-session": "*",
"slim/slim": "^2.6", "ext-xml": "*",
"easybook/geshi": "^1.0.8",
"amenadiel/jpgraph": "^3.6", "amenadiel/jpgraph": "^3.6",
"tecnickcom/tcpdf": "~6.2.0",
"xjtuwangke/passwordhash": "dev-master",
"pear/console_color2": "^0.1",
"pear/console_table": "^1.3",
"dapphp/radius": "^2.0", "dapphp/radius": "^2.0",
"php-amqplib/php-amqplib": "^2.0", "doctrine/dbal": "^2.9",
"symfony/yaml": "^4.0", "easybook/geshi": "^1.0.8",
"rmccue/requests": "^1.7", "ezyang/htmlpurifier": "^4.8",
"palanik/corsslim": "^1.1",
"influxdb/influxdb-php": "^1.14",
"oriceon/toastr-5-laravel": "dev-master",
"wpb/string-blade-compiler": "3.7.x-dev",
"fico7489/laravel-pivot": "^3.0", "fico7489/laravel-pivot": "^3.0",
"fideloper/proxy": "^4.0", "fideloper/proxy": "^4.0",
"doctrine/dbal": "^2.9" "influxdb/influxdb-php": "^1.14",
"laravel/laravel": "5.7.*",
"oriceon/toastr-5-laravel": "dev-master",
"pear/console_color2": "^0.1",
"pear/console_table": "^1.3",
"php-amqplib/php-amqplib": "^2.0",
"phpmailer/phpmailer": "~6.0",
"rmccue/requests": "^1.7",
"spatie/laravel-cors": "1.3.*",
"symfony/yaml": "^4.0",
"tecnickcom/tcpdf": "~6.2.0",
"wpb/string-blade-compiler": "3.7.x-dev",
"xjtuwangke/passwordhash": "dev-master"
}, },
"require-dev": { "require-dev": {
"barryvdh/laravel-debugbar": "^3.2", "barryvdh/laravel-debugbar": "^3.2",

114
composer.lock generated
View File

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "c28a0e8f4179b98ae34fce9c7c226687", "content-hash": "0e65f16ae5fd7aa4574cb9a40a419e0d",
"packages": [ "packages": [
{ {
"name": "amenadiel/jpgraph", "name": "amenadiel/jpgraph",
@ -2122,50 +2122,6 @@
], ],
"time": "2018-04-30T05:58:02+00:00" "time": "2018-04-30T05:58:02+00:00"
}, },
{
"name": "palanik/corsslim",
"version": "v1.1.0",
"source": {
"type": "git",
"url": "https://github.com/palanik/CorsSlim.git",
"reference": "ebd2bca1fcf4711a69db43f65bb63d10c7016030"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/palanik/CorsSlim/zipball/ebd2bca1fcf4711a69db43f65bb63d10c7016030",
"reference": "ebd2bca1fcf4711a69db43f65bb63d10c7016030",
"shasum": ""
},
"require": {
"slim/slim": ">=2.4.0 <3.0"
},
"type": "library",
"autoload": {
"psr-4": {
"CorsSlim\\": "."
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "palanik"
}
],
"description": "Cross-origin resource sharing (CORS) middleware for PHP Slim.",
"homepage": "https://github.com/palanik/CorsSlim",
"keywords": [
"cors",
"corsslim",
"cross-origin",
"preflight",
"slim",
"slimphp"
],
"time": "2015-12-16T23:57:06+00:00"
},
{ {
"name": "paragonie/random_compat", "name": "paragonie/random_compat",
"version": "v9.99.99", "version": "v9.99.99",
@ -3080,30 +3036,38 @@
"time": "2016-10-13T00:11:37+00:00" "time": "2016-10-13T00:11:37+00:00"
}, },
{ {
"name": "slim/slim", "name": "spatie/laravel-cors",
"version": "2.6.3", "version": "1.3.3",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/slimphp/Slim.git", "url": "https://github.com/spatie/laravel-cors.git",
"reference": "9224ed81ac1c412881e8d762755e3d76ebf580c0" "reference": "3395a43f797b1e946a1697be644c3cb4d8dc83dd"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/slimphp/Slim/zipball/9224ed81ac1c412881e8d762755e3d76ebf580c0", "url": "https://api.github.com/repos/spatie/laravel-cors/zipball/3395a43f797b1e946a1697be644c3cb4d8dc83dd",
"reference": "9224ed81ac1c412881e8d762755e3d76ebf580c0", "reference": "3395a43f797b1e946a1697be644c3cb4d8dc83dd",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"php": ">=5.3.0" "illuminate/support": "5.5.*|5.6.*|5.7.*|5.8.*",
"php": "^7.0"
}, },
"suggest": { "require-dev": {
"ext-mcrypt": "Required for HTTP cookie encryption", "orchestra/testbench": "3.5.*|3.6.*|3.7.*|3.8.*",
"phpseclib/mcrypt_compat": "Polyfil for mcrypt extension" "phpunit/phpunit": "^6.5.4|^7.0"
}, },
"type": "library", "type": "library",
"extra": {
"laravel": {
"providers": [
"Spatie\\Cors\\CorsServiceProvider"
]
}
},
"autoload": { "autoload": {
"psr-0": { "psr-4": {
"Slim": "." "Spatie\\Cors\\": "src"
} }
}, },
"notification-url": "https://packagist.org/downloads/", "notification-url": "https://packagist.org/downloads/",
@ -3112,19 +3076,23 @@
], ],
"authors": [ "authors": [
{ {
"name": "Josh Lockhart", "name": "Freek Van der Herten",
"email": "info@joshlockhart.com", "email": "freek@spatie.be",
"homepage": "http://www.joshlockhart.com/" "homepage": "https://spatie.be",
"role": "Developer"
} }
], ],
"description": "Slim Framework, a PHP micro framework", "description": "Send CORS headers in a Laravel or Lumen application",
"homepage": "http://github.com/codeguy/Slim", "homepage": "https://github.com/spatie/laravel-cors",
"keywords": [ "keywords": [
"microframework", "ajax",
"rest", "api",
"router" "cors",
"laravel-cors",
"request",
"spatie"
], ],
"time": "2017-01-07T12:21:41+00:00" "time": "2019-02-27T07:56:32+00:00"
}, },
{ {
"name": "swiftmailer/swiftmailer", "name": "swiftmailer/swiftmailer",
@ -7759,22 +7727,22 @@
"aliases": [], "aliases": [],
"minimum-stability": "stable", "minimum-stability": "stable",
"stability-flags": { "stability-flags": {
"xjtuwangke/passwordhash": 20,
"oriceon/toastr-5-laravel": 20, "oriceon/toastr-5-laravel": 20,
"wpb/string-blade-compiler": 20 "wpb/string-blade-compiler": 20,
"xjtuwangke/passwordhash": 20
}, },
"prefer-stable": false, "prefer-stable": false,
"prefer-lowest": false, "prefer-lowest": false,
"platform": { "platform": {
"php": "^7.1.3", "php": "^7.1.3",
"ext-pdo": "*",
"ext-pcre": "*",
"ext-curl": "*", "ext-curl": "*",
"ext-session": "*",
"ext-xml": "*",
"ext-gd": "*", "ext-gd": "*",
"ext-json": "*", "ext-json": "*",
"ext-mbstring": "*" "ext-mbstring": "*",
"ext-pcre": "*",
"ext-pdo": "*",
"ext-session": "*",
"ext-xml": "*"
}, },
"platform-dev": [] "platform-dev": []
} }

61
config/cors.php Normal file
View File

@ -0,0 +1,61 @@
<?php
return [
/*
* A cors profile determines which origins, methods, headers are allowed for
* a given requests. The `DefaultProfile` reads its configuration from this
* config file.
*
* You can easily create your own cors profile.
* More info: https://github.com/spatie/laravel-cors/#creating-your-own-cors-profile
*/
'cors_profile' => App\Http\Profile\CorsApiProfile::class,
/*
* This configuration is used by `DefaultProfile`.
*/
'default_profile' => [
'allow_credentials' => false,
'allow_origins' => [
'*',
],
'allow_methods' => [
'POST',
'GET',
'OPTIONS',
'PUT',
'PATCH',
'DELETE',
],
'allow_headers' => [
'Content-Type',
'X-Auth-Token',
'Origin',
'Authorization',
],
'expose_headers' => [
'Cache-Control',
'Content-Language',
'Content-Type',
'Expires',
'Last-Modified',
'Pragma',
],
'forbidden_response' => [
'message' => 'Forbidden (cors).',
'status' => 403,
],
/*
* Preflight request will respond with value for the max age header.
*/
'max_age' => 60 * 60 * 24,
],
];

View File

@ -279,16 +279,14 @@ Input (JSON):
Example: Example:
```curl ```curl
curl -X POST -d '{"device_id":[1,2,3], "name": "testrule", builder":"{\"condition\":\"AND\",\"rules\":[{\"id\":\"devices.hostname\",\"field\":\"devices.hostname\",\"type\":\"string\",\"input\":\"text\",\"operator\":\"equal\",\"value\":\"localhost\"}],\"valid\":true}","severity": "critical","count":15,"delay":"5 m","mute":false}' -H 'X-Auth-Token: YOURAPITOKENHERE' https://librenms.org/api/v0/rules curl -X POST -d '{"devices":[1,2,3], "name": "testrule", "builder":"{"condition":"AND","rules":[{"id":"devices.hostname","field":"devices.hostname","type":"string","input":"text","operator":"equal","value":"localhost"}],"valid":true}","severity": "critical","count":15,"delay":"5 m","mute":false}' -H 'X-Auth-Token: YOURAPITOKENHERE' https://librenms.org/api/v0/rules
``` ```
Output: Output:
```json ```json
rules
{ {
"status": "ok", "status": "ok"
"message": ""
} }
``` ```
@ -322,15 +320,13 @@ Input (JSON):
Example: Example:
```curl ```curl
curl -X PUT -d '{"rule_id":1,"device_id":"-1", "name": "testrule", "builder":"{\"condition\":\"AND\",\"rules\":[{\"id\":\"devices.hostname\",\"field\":\"devices.hostname\",\"type\":\"string\",\"input\":\"text\",\"operator\":\"equal\",\"value\":\"localhost\"}],\"valid\":true}","severity": "critical","count":15,"delay":"5 m","mute":false}' -H 'X-Auth-Token: YOURAPITOKENHERE' https://librenms.org/api/v0/rules curl -X PUT -d '{"rule_id":1,"device_id":"-1", "name": "testrule", "builder":"{"condition":"AND","rules":[{"id":"devices.hostname","field":"devices.hostname","type":"string","input":"text","operator":"equal","value":"localhost"}],"valid":true}","severity": "critical","count":15,"delay":"5 m","mute":false}' -H 'X-Auth-Token: YOURAPITOKENHERE' https://librenms.org/api/v0/rules
``` ```
Output: Output:
```json ```json
rules
{ {
"status": "ok", "status": "ok"
"message": ""
} }
``` ```

View File

@ -858,8 +858,10 @@ the standard options, all of which you can configure.
```php ```php
$config['api']['cors']['enabled'] = false; $config['api']['cors']['enabled'] = false;
$config['api']['cors']['origin'] = '*'; $config['api']['cors']['origin'] = ['*'];
$config['api']['cors']['maxage'] = '86400'; $config['api']['cors']['maxage'] = '86400';
$config['api']['cors']['allowmethods'] = array('POST', 'GET', 'PUT', 'DELETE', 'PATCH'); $config['api']['cors']['allowmethods'] = ['POST', 'GET', 'PUT', 'DELETE', 'PATCH'];
$config['api']['cors']['allowheaders'] = array('Origin', 'X-Requested-With', 'Content-Type', 'Accept', 'X-Auth-Token'); $config['api']['cors']['allowheaders'] = ['Origin', 'X-Requested-With', 'Content-Type', 'Accept', 'X-Auth-Token'];
$config['api']['cors']['exposeheaders'] = ['Cache-Control', 'Content-Language', 'Content-Type', 'Expires', 'Last-Modified', 'Pragma'];
$config['api']['cors']['allowcredentials'] = false;
``` ```

View File

@ -1 +0,0 @@
index.php

60
html/api_v0.php Normal file
View File

@ -0,0 +1,60 @@
<?php
/**
* Laravel - A PHP Framework For Web Artisans
*
* @package Laravel
* @author Taylor Otwell <taylor@laravel.com>
*/
/*
|--------------------------------------------------------------------------
| Register The Auto Loader
|--------------------------------------------------------------------------
|
| Composer provides a convenient, automatically generated class loader for
| our application. We just need to utilize it! We'll simply require it
| into the script here so that we don't have to worry about manual
| loading any of our classes later on. It feels great to relax.
|
*/
require __DIR__.'/../bootstrap/autoload.php';
/*
|--------------------------------------------------------------------------
| Turn On The Lights
|--------------------------------------------------------------------------
|
| We need to illuminate PHP development, so let us turn on the lights.
| This bootstraps the framework and gets it ready for use, then it
| will load up this application so that we can run it and send
| the responses back to the browser and delight our users.
|
*/
$app = require_once __DIR__.'/../bootstrap/app.php';
/*
|--------------------------------------------------------------------------
| Run The Application
|--------------------------------------------------------------------------
|
| Once we have the application, we can handle the incoming request
| through the kernel, and send the associated response back to
| the client's browser allowing them to enjoy the creative
| and wonderful application we have prepared for them.
|
*/
$kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);
$_SERVER['HTTP_ACCEPT'] = 'application/json'; // force json accepted
$response = $kernel->handle(
$request = Illuminate\Http\Request::capture()
);
$response->send();
$kernel->terminate($request, $response);

File diff suppressed because it is too large Load Diff

View File

@ -12,7 +12,6 @@
* @copyright (C) 2013 LibreNMS Group * @copyright (C) 2013 LibreNMS Group
*/ */
use LibreNMS\Authentication\LegacyAuth;
use LibreNMS\Config; use LibreNMS\Config;
/** /**
@ -288,11 +287,11 @@ function print_graph_popup($graph_array)
function bill_permitted($bill_id) function bill_permitted($bill_id)
{ {
if (LegacyAuth::user()->hasGlobalRead()) { if (Auth::user()->hasGlobalRead()) {
return true; return true;
} }
return \Permissions::canAccessBill($bill_id, LegacyAuth::id()); return \Permissions::canAccessBill($bill_id, Auth::id());
} }
function port_permitted($port_id, $device_id = null) function port_permitted($port_id, $device_id = null)
@ -305,7 +304,7 @@ function port_permitted($port_id, $device_id = null)
return true; return true;
} }
return \Permissions::canAccessPort($port_id, LegacyAuth::id()); return \Permissions::canAccessPort($port_id, Auth::id());
} }
function application_permitted($app_id, $device_id = null) function application_permitted($app_id, $device_id = null)
@ -323,10 +322,10 @@ function application_permitted($app_id, $device_id = null)
function device_permitted($device_id) function device_permitted($device_id)
{ {
if (LegacyAuth::user()->hasGlobalRead()) { if (Auth::user()->hasGlobalRead()) {
return true; return true;
} }
return \Permissions::canAccessDevice($device_id, LegacyAuth::id()); return \Permissions::canAccessDevice($device_id, Auth::id());
} }
function print_graph_tag($args) function print_graph_tag($args)
@ -686,11 +685,11 @@ function devclass($device)
function getlocations() function getlocations()
{ {
if (LegacyAuth::user()->hasGlobalRead()) { if (Auth::user()->hasGlobalRead()) {
return dbFetchRows('SELECT id, location FROM locations ORDER BY location'); return dbFetchRows('SELECT id, location FROM locations ORDER BY location');
} }
return dbFetchRows('SELECT id, L.location FROM devices AS D, locations AS L, devices_perms AS P WHERE D.device_id = P.device_id AND P.user_id = ? AND D.location_id = L.id ORDER BY location', [LegacyAuth::id()]); return dbFetchRows('SELECT id, L.location FROM devices AS D, locations AS L, devices_perms AS P WHERE D.device_id = P.device_id AND P.user_id = ? AND D.location_id = L.id ORDER BY location', [Auth::id()]);
} }

View File

@ -168,12 +168,7 @@ if ($error_msg) {
} }
} else { } else {
if ($output === 'base64') { if ($output === 'base64') {
$fd = fopen($graphfile, 'r'); $imagedata = file_get_contents($graphfile);
ob_start();
fpassthru($fd);
$imagedata = ob_get_contents();
fclose($fd);
ob_end_clean();
$base64_output = base64_encode($imagedata); $base64_output = base64_encode($imagedata);
} else { } else {
$fd = fopen($graphfile, 'r'); $fd = fopen($graphfile, 'r');

View File

@ -1,238 +0,0 @@
<?php
/*
* LibreNMS
*
* Copyright (c) 2014 Neil Lathwood <https://github.com/laf/ http://www.lathwood.co.uk/fa>
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version. Please see LICENSE.txt at the top level of
* the source code distribution for details.
*/
use LibreNMS\Config;
$init_modules = array('web', 'alerts');
require realpath(__DIR__ . '/..') . '/init.php';
if (!Auth::check()) {
die('Unauthorized');
}
$app = new \Slim\Slim();
if (Config::get('api.cors.enabled') === true) {
$corsOptions = array(
"origin" => Config::get('api.cors.origin'),
"maxAge" => Config::get('api.cors.maxage'),
"allowMethods" => Config::get('api.cors.allowmethods'),
"allowHeaders" => Config::get('api.cors.allowheaders'),
);
$cors = new \CorsSlim\CorsSlim($corsOptions);
$app->add($cors);
}
require Config::get('install_dir') . '/includes/html/api_functions.inc.php';
$app->setName('api');
$app->notFound(function () use ($app) {
api_error(404, "This API route doesn't exist.");
});
$app->group(
'/api',
function () use ($app) {
$app->group(
'/v0',
function () use ($app) {
$app->get('/system', 'authToken', 'server_info')->name('server_info');
$app->get('/bgp', 'authToken', 'list_bgp')->name('list_bgp');
$app->get('/bgp/:id', 'authToken', 'get_bgp')->name('get_bgp');
$app->get('/ospf', 'authToken', 'list_ospf')->name('list_ospf');
// api/v0/bgp
$app->get('/oxidized(/:hostname)', 'authToken', 'list_oxidized')->name('list_oxidized');
$app->group(
'/devices',
function () use ($app) {
$app->delete('/:hostname', 'authToken', 'del_device')->name('del_device');
// api/v0/devices/$hostname
$app->get('/:hostname', 'authToken', 'get_device')->name('get_device');
// api/v0/devices/$hostname
$app->patch('/:hostname', 'authToken', 'update_device')->name('update_device_field');
$app->patch('/:hostname/rename/:new_hostname', 'authToken', 'rename_device')->name('rename_device');
$app->get('/:hostname/vlans', 'authToken', 'get_vlans')->name('get_vlans');
// api/v0/devices/$hostname/vlans
$app->get('/:hostname/links', 'authToken', 'list_links')->name('get_links');
// api/v0/devices/$hostname/links
$app->get('/:hostname/graphs', 'authToken', 'get_graphs')->name('get_graphs');
// api/v0/devices/$hostname/graphs
$app->get('/:hostname/fdb', 'authToken', 'get_fdb')->name('get_fdb');
// api/v0/devices/$hostname/fdb
$app->get('/:hostname/health(/:type)(/:sensor_id)', 'authToken', 'list_available_health_graphs')->name('list_available_health_graphs');
$app->get('/:hostname/wireless(/:type)(/:sensor_id)', 'authToken', 'list_available_wireless_graphs')->name('list_available_wireless_graphs');
$app->get('/:hostname/ports', 'authToken', 'get_port_graphs')->name('get_port_graphs');
$app->get('/:hostname/ip', 'authToken', 'get_ip_addresses')->name('get_device_ip_addresses');
$app->get('/:hostname/port_stack', 'authToken', 'get_port_stack')->name('get_port_stack');
// api/v0/devices/$hostname/ports
$app->get('/:hostname/components', 'authToken', 'get_components')->name('get_components');
$app->post('/:hostname/components/:type', 'authToken', 'add_components')->name('add_components');
$app->put('/:hostname/components', 'authToken', 'edit_components')->name('edit_components');
$app->delete('/:hostname/components/:component', 'authToken', 'delete_components')->name('delete_components');
$app->get('/:hostname/groups', 'authToken', 'get_device_groups')->name('get_device_groups');
$app->get('/:hostname/graphs/health/:type(/:sensor_id)', 'authToken', 'get_graph_generic_by_hostname')->name('get_health_graph');
$app->get('/:hostname/graphs/wireless/:type(/:sensor_id)', 'authToken', 'get_graph_generic_by_hostname')->name('get_wireless_graph');
$app->get('/:hostname/:type', 'authToken', 'get_graph_generic_by_hostname')->name('get_graph_generic_by_hostname');
// api/v0/devices/$hostname/$type
$app->get('/:hostname/ports/:ifname', 'authToken', 'get_port_stats_by_port_hostname')->name('get_port_stats_by_port_hostname');
// api/v0/devices/$hostname/ports/$ifName
$app->get('/:hostname/ports/:ifname/:type', 'authToken', 'get_graph_by_port_hostname')->name('get_graph_by_port_hostname');
// api/v0/devices/$hostname/ports/$ifName/$type
}
);
$app->get('/devices', 'authToken', 'list_devices')->name('list_devices');
// api/v0/devices
$app->post('/devices', 'authToken', 'add_device')->name('add_device');
// api/v0/devices (json data needs to be passed)
$app->group(
'/devicegroups',
function () use ($app) {
$app->get('/:name', 'authToken', 'get_devices_by_group')->name('get_devices_by_group');
}
);
$app->get('/devicegroups', 'authToken', 'get_device_groups')->name('get_devicegroups');
$app->group(
'/ports',
function () use ($app) {
$app->get('/:portid', 'authToken', 'get_port_info')->name('get_port_info');
$app->get('/:portid/ip', 'authToken', 'get_ip_addresses')->name('get_port_ip_info');
}
);
$app->get('/ports', 'authToken', 'get_all_ports')->name('get_all_ports');
$app->group(
'/portgroups',
function () use ($app) {
$app->get('/multiport/bits/:id', 'authToken', 'get_graph_by_portgroup')->name('get_graph_by_portgroup_multiport_bits');
$app->get('/:group', 'authToken', 'get_graph_by_portgroup')->name('get_graph_by_portgroup');
}
);
$app->group(
'/bills',
function () use ($app) {
$app->get('/:bill_id', 'authToken', 'list_bills')->name('get_bill');
$app->delete('/:id', 'authToken', 'delete_bill')->name('delete_bill');
// api/v0/bills/$bill_id
$app->get('/:bill_id/graphs/:graph_type', 'authToken', 'get_bill_graph')->name('get_bill_graph');
$app->get('/:bill_id/graphdata/:graph_type', 'authToken', 'get_bill_graphdata')->name('get_bill_graphdata');
$app->get('/:bill_id/history', 'authToken', 'get_bill_history')->name('get_bill_history');
$app->get('/:bill_id/history/:bill_hist_id/graphs/:graph_type', 'authToken', 'get_bill_history_graph')->name('get_bill_history_graph');
$app->get('/:bill_id/history/:bill_hist_id/graphdata/:graph_type', 'authToken', 'get_bill_history_graphdata')->name('get_bill_history_graphdata');
}
);
$app->get('/bills', 'authToken', 'list_bills')->name('list_bills');
$app->post('/bills', 'authToken', 'create_edit_bill')->name('create_bill');
// api/v0/bills
// /api/v0/alerts
$app->group(
'/alerts',
function () use ($app) {
$app->get('/:id', 'authToken', 'list_alerts')->name('get_alert');
// api/v0/alerts
$app->put('/:id', 'authToken', 'ack_alert')->name('ack_alert');
// api/v0/alerts/$id (PUT)
$app->put('/unmute/:id', 'authToken', 'unmute_alert')->name('unmute_alert');
// api/v0/alerts/unmute/$id (PUT)
}
);
$app->get('/alerts', 'authToken', 'list_alerts')->name('list_alerts');
// api/v0/alerts
// /api/v0/rules
$app->group(
'/rules',
function () use ($app) {
$app->get('/:id', 'authToken', 'list_alert_rules')->name('get_alert_rule');
// api/v0/rules/$id
$app->delete('/:id', 'authToken', 'delete_rule')->name('delete_rule');
// api/v0/rules/$id (DELETE)
}
);
$app->get('/rules', 'authToken', 'list_alert_rules')->name('list_alert_rules');
// api/v0/rules
$app->post('/rules', 'authToken', 'add_edit_rule')->name('add_rule');
// api/v0/rules (json data needs to be passed)
$app->put('/rules', 'authToken', 'add_edit_rule')->name('edit_rule');
// api/v0/rules (json data needs to be passed)
// Inventory section
$app->group(
'/inventory',
function () use ($app) {
$app->get('/:hostname', 'authToken', 'get_inventory')->name('get_inventory');
}
);
// End Inventory
// Routing section
$app->group(
'/routing',
function () use ($app) {
$app->get('/bgp/cbgp', 'authToken', 'list_cbgp')->name('list_cbgp');
$app->get('/vrf', 'authToken', 'list_vrf')->name('list_vrf');
$app->get('/vrf/:id', 'authToken', 'get_vrf')->name('get_vrf');
$app->group(
'/ipsec',
function () use ($app) {
$app->get('/data/:hostname', 'authToken', 'list_ipsec')->name('list_ipsec');
}
);
}
);
// End Routing
// Resources section
$app->group(
'/resources',
function () use ($app) {
$app->get('/fdb/', 'authToken', 'list_fdb')->name('list_fdb');
$app->get('/fdb/:mac', 'authToken', 'list_fdb')->name('list_fdb_mac');
$app->get('/links', 'authToken', 'list_links')->name('list_links');
$app->get('/links/:id', 'authToken', 'get_link')->name('get_link');
$app->get('/locations', 'authToken', 'list_locations')->name('list_locations');
$app->get('/sensors', 'authToken', 'list_sensors')->name('list_sensors');
$app->get('/vlans', 'authToken', 'list_vlans')->name('list_vlans');
$app->group(
'/ip',
function () use ($app) {
$app->get('/addresses/', 'authToken', 'list_ip_addresses')->name('list_ip_addresses');
$app->get('/arp/:ip', 'authToken', 'list_arp')->name('list_arp')->conditions(array('ip' => '[^?]+'));
$app->get('/networks/', 'authToken', 'list_ip_networks')->name('list_ip_networks');
$app->get('/networks/:id/ip', 'authToken', 'get_ip_addresses')->name('get_network_ip_addresses');
}
);
}
);
// End Resources
// Service section
$app->group(
'/services',
function () use ($app) {
$app->get('/:hostname', 'authToken', 'list_services')->name('get_service_for_host');
$app->post('/:hostname', 'authToken', 'add_service_for_host')->name('add_service_for_host');
}
);
$app->get('/services', 'authToken', 'list_services')->name('list_services');
// End Service
$app->group(
'/logs',
function () use ($app) {
$app->get('/eventlog(/:hostname)', 'authToken', 'list_logs')->name('list_eventlog');
$app->get('/syslog(/:hostname)', 'authToken', 'list_logs')->name('list_syslog');
$app->get('/alertlog(/:hostname)', 'authToken', 'list_logs')->name('list_alertlog');
$app->get('/authlog(/:hostname)', 'authToken', 'list_logs')->name('list_authlog');
}
);
}
);
$app->get('/v0', 'authToken', 'show_endpoints');
// api/v0
}
);
$app->run();

View File

@ -11,5 +11,125 @@
| |
*/ */
// Legacy API
Route::any('/v0/{path?}', 'LegacyController@api')->where('path', '.*');
Route::group(['prefix' => 'v0', 'namespace' => '\App\Api\Controllers'], function () {
Route::get('system', 'LegacyApiController@server_info')->name('server_info');
Route::get(null, 'LegacyApiController@show_endpoints');
// global read only access required
Route::middleware(['can:global-read'])->group(function () {
Route::get('bgp', 'LegacyApiController@list_bgp')->name('list_bgp');
Route::get('bgp/{id}', 'LegacyApiController@get_bgp')->name('get_bgp');
Route::get('ospf', 'LegacyApiController@list_ospf')->name('list_ospf');
Route::get('oxidized/{hostname?}', 'LegacyApiController@list_oxidized')->name('list_oxidized');
Route::get('devicegroups/{name}', 'LegacyApiController@get_devices_by_group')->name('get_devices_by_group');
Route::get('devicegroups', 'LegacyApiController@get_device_groups')->name('get_device_groups');
Route::get('portgroups/multiport/bits/{id}', 'LegacyApiController@get_graph_by_portgroup')->name('get_graph_by_portgroup_multiport_bits');
Route::get('portgroups/{group}', 'LegacyApiController@get_graph_by_portgroup')->name('get_graph_by_portgroup');
Route::get('alerts/{id}', 'LegacyApiController@list_alerts')->name('get_alert');
Route::get('alerts', 'LegacyApiController@list_alerts')->name('list_alerts');
Route::get('rules/{id}', 'LegacyApiController@list_alert_rules')->name('get_alert_rule');
Route::get('rules', 'LegacyApiController@list_alert_rules')->name('list_alert_rules');
Route::get('routing/vrf/{id}', 'LegacyApiController@get_vrf')->name('get_vrf');
Route::get('routing/ipsec/data/{hostname}', 'LegacyApiController@list_ipsec')->name('list_ipsec');
Route::get('services', 'LegacyApiController@list_services')->name('list_services');
Route::get('services/{hostname}', 'LegacyApiController@list_services')->name('list_services');
Route::group(['prefix' => 'resources'], function () {
Route::get('links/{id}', 'LegacyApiController@get_link')->name('get_link');
Route::get('locations', 'LegacyApiController@list_locations')->name('list_locations');
Route::get('ip/addresses', 'LegacyApiController@list_ip_addresses')->name('list_ip_addresses');
Route::get('ip/arp/{ip}', 'LegacyApiController@list_arp')->name('list_arp');
Route::get('ip/networks', 'LegacyApiController@list_ip_networks')->name('list_ip_networks');
Route::get('ip/networks/{id}/ip', 'LegacyApiController@get_network_ip_addresses')->name('get_network_ip_addresses');
});
Route::group(['prefix' => 'logs'], function () {
Route::get('eventlog/{hostname?}', 'LegacyApiController@list_logs')->name('list_eventlog');
Route::get('syslog/{hostname?}', 'LegacyApiController@list_logs')->name('list_syslog');
Route::get('alertlog/{hostname?}', 'LegacyApiController@list_logs')->name('list_alertlog');
Route::get('authlog', 'LegacyApiController@list_logs')->name('list_authlog');
});
});
// admin required
Route::middleware(['can:admin'])->group(function () {
Route::group(['prefix' => 'devices'], function () {
Route::post(null, 'LegacyApiController@add_device')->name('add_device');
Route::delete('{hostname}', 'LegacyApiController@del_device')->name('del_device');
Route::patch('{hostname}', 'LegacyApiController@update_device')->name('update_device_field');
Route::patch('{hostname}/rename/{new_hostname}', 'LegacyApiController@rename_device')->name('rename_device');
Route::post('{hostname}/components/{type}', 'LegacyApiController@add_components')->name('add_components');
Route::put('{hostname}/components', 'LegacyApiController@edit_components')->name('edit_components');
Route::delete('{hostname}/components/{component}', 'LegacyApiController@delete_components')->name('delete_components');
});
Route::post('bills', 'LegacyApiController@create_edit_bill')->name('create_bill');
Route::delete('bills/{bill_id}', 'LegacyApiController@delete_bill')->name('delete_bill');
Route::put('alerts/{id}', 'LegacyApiController@ack_alert')->name('ack_alert');
Route::put('alerts/unmute/{id}', 'LegacyApiController@unmute_alert')->name('unmute_alert');
Route::post('rules', 'LegacyApiController@add_edit_rule')->name('add_rule');
Route::put('rules', 'LegacyApiController@add_edit_rule')->name('edit_rule');
Route::delete('rules/{id}', 'LegacyApiController@delete_rule')->name('delete_rule');
Route::post('services/{hostname}', 'LegacyApiController@add_service_for_host')->name('add_service_for_host');
});
// restricted by access
Route::group(['prefix' => 'devices'], function () {
Route::get('{hostname}', 'LegacyApiController@get_device')->name('get_device');
Route::get('{hostname}/graphs/health/{type}/{sensor_id?}', 'LegacyApiController@get_graph_generic_by_hostname')->name('get_health_graph');
Route::get('{hostname}/graphs/wireless/{type}/{sensor_id?}', 'LegacyApiController@get_graph_generic_by_hostname')->name('get_wireless_graph');
Route::get('{hostname}/vlans', 'LegacyApiController@get_vlans')->name('get_vlans');
Route::get('{hostname}/links', 'LegacyApiController@list_links')->name('list_links');
Route::get('{hostname}/graphs', 'LegacyApiController@get_graphs')->name('get_graphs');
Route::get('{hostname}/fdb', 'LegacyApiController@get_fdb')->name('get_fdb');
Route::get('{hostname}/health/{type?}/{sensor_id?}', 'LegacyApiController@list_available_health_graphs')->name('list_available_health_graphs');
Route::get('{hostname}/wireless/{type?}/{sensor_id?}', 'LegacyApiController@list_available_wireless_graphs')->name('list_available_wireless_graphs');
Route::get('{hostname}/ports', 'LegacyApiController@get_port_graphs')->name('get_port_graphs');
Route::get('{hostname}/ip', 'LegacyApiController@get_device_ip_addresses')->name('get_ip_addresses');
Route::get('{hostname}/port_stack', 'LegacyApiController@get_port_stack')->name('get_port_stack');
Route::get('{hostname}/components', 'LegacyApiController@get_components')->name('get_components');
Route::get('{hostname}/groups', 'LegacyApiController@get_device_groups')->name('get_device_groups');
Route::get('{hostname}/ports/{ifname}', 'LegacyApiController@get_port_stats_by_port_hostname')->name('get_port_stats_by_port_hostname');
Route::get('{hostname}/ports/{ifname}/{type}', 'LegacyApiController@get_graph_by_port_hostname')->name('get_graph_by_port_hostname');
Route::get('{hostname}/{type}', 'LegacyApiController@get_graph_generic_by_hostname')->name('get_graph_generic_by_hostname');
Route::get(null, 'LegacyApiController@list_devices')->name('list_devices');
});
Route::group(['prefix' => 'ports'], function () {
Route::get('{portid}', 'LegacyApiController@get_port_info')->name('get_port_info');
Route::get('{portid}/ip', 'LegacyApiController@get_port_ip_addresses')->name('get_port_ip_info');
Route::get(null, 'LegacyApiController@get_all_ports')->name('get_all_ports');
});
Route::group(['prefix' => 'bills'], function () {
Route::get(null, 'LegacyApiController@list_bills')->name('list_bills');
Route::get('{bill_id}', 'LegacyApiController@list_bills')->name('get_bill');
Route::get('{bill_id}/graphs/{graph_type}', 'LegacyApiController@get_bill_graph')->name('get_bill_graph');
Route::get('{bill_id}/graphdata/{graph_type}', 'LegacyApiController@get_bill_graphdata')->name('get_bill_graphdata');
Route::get('{bill_id}/history', 'LegacyApiController@get_bill_history')->name('get_bill_history');
Route::get('{bill_id}/history/{bill_hist_id}/graphs/{graph_type}', 'LegacyApiController@get_bill_history_graph')->name('get_bill_history_graph');
Route::get('{bill_id}/history/{bill_hist_id}/graphdata/{graph_type}', 'LegacyApiController@get_bill_history_graphdata')->name('get_bill_history_graphdata');
});
Route::group(['prefix' => 'routing'], function () {
Route::get('bgp/cbgp', 'LegacyApiController@list_cbgp')->name('list_cbgp');
Route::get('vrf', 'LegacyApiController@list_vrf')->name('list_vrf');
});
Route::group(['prefix' => 'resources'], function () {
Route::get('fdb', 'LegacyApiController@list_fdb')->name('list_fdb');
Route::get('fdb/{mac}', 'LegacyApiController@list_fdb')->name('list_fdb_mac');
Route::get('links', 'LegacyApiController@list_links')->name('list_links');
Route::get('sensors', 'LegacyApiController@list_sensors')->name('list_sensors');
Route::get('vlans', 'LegacyApiController@list_vlans')->name('list_vlans');
});
Route::get('inventory/{hostname}', 'LegacyApiController@get_inventory')->name('get_inventory');
// Route not found
Route::any('/{path?}', 'LegacyApiController@api_not_found')->where('path', '.*');
});

51
tests/BasicApiTest.php Normal file
View File

@ -0,0 +1,51 @@
<?php
/**
* BasicApiTest.php
*
* -Description-
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @package LibreNMS
* @link http://librenms.org
* @copyright 2019 Tony Murray
* @author Tony Murray <murraytony@gmail.com>
*/
namespace LibreNMS\Tests;
use App\Models\ApiToken;
use App\Models\Device;
use App\Models\User;
use Illuminate\Foundation\Testing\DatabaseTransactions;
class BasicApiTest extends DBTestCase
{
use DatabaseTransactions;
public function testListDevices()
{
$user = factory(User::class)->state('admin')->create();
$token = ApiToken::generateToken($user);
$device = factory(Device::class)->create();
$this->json('GET', '/api/v0/devices', [], ['X-Auth-Token' => $token->token_hash])
->assertStatus(200)
->assertJson([
"status" => "ok",
"devices" => [$device->toArray()],
"count"=> 1
]);
}
}