mirror of
https://github.com/donl/gPanel.git
synced 2026-06-30 06:12:06 -06:00
Merge pull request #95 from george-e-shaw-iv/master
Implimented IP filtering addition in account panel
This commit is contained in:
commit
40e1e3d9d6
14 changed files with 338 additions and 49 deletions
22
account/assets/js/panelHandlers/security/filter_ip.js
Normal file
22
account/assets/js/panelHandlers/security/filter_ip.js
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
var ipModal = jQuery('.ip-filter-modal');
|
||||
|
||||
jQuery('._js_ip-filter-form').on('submit', function(e){
|
||||
e.preventDefault();
|
||||
|
||||
var requestData = {};
|
||||
requestData["ip"] = jQuery(this).find('input[name="ip"]').val();
|
||||
requestData["type"] = jQuery(this).find('input[name="type"]').val();
|
||||
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open(jQuery(this).attr('method'), jQuery(this).attr('action'), true);
|
||||
xhr.send(JSON.stringify(requestData));
|
||||
|
||||
xhr.onloadend = function() {
|
||||
if (xhr.status == 204) {
|
||||
listFilteredIPs(requestData["type"]);
|
||||
}
|
||||
else {
|
||||
alert("Something went wrong trying to filter that IP, please contact your administrator if problem persists.");
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
@ -1,22 +0,0 @@
|
|||
var ipModal = jQuery('.ip-filter-modal');
|
||||
|
||||
jQuery('._js_ip-filtering-open').on('click', function(e){
|
||||
e.preventDefault();
|
||||
|
||||
var title;
|
||||
switch(jQuery(this).attr('data')) {
|
||||
case "general":
|
||||
title = "General";
|
||||
break;
|
||||
case "maintenance":
|
||||
title = "Maintenance Mode";
|
||||
break;
|
||||
default:
|
||||
alert("Error, refresh and try again. If problem persists contact server administrator.");
|
||||
return;
|
||||
}
|
||||
title += " IP Filtering";
|
||||
|
||||
ipModal.find('.modal-title').html(title);
|
||||
ipModal.modal('show');
|
||||
});
|
||||
66
account/assets/js/panelHandlers/security/ip_list.js
Normal file
66
account/assets/js/panelHandlers/security/ip_list.js
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
var ipModal = jQuery('.ip-filter-modal');
|
||||
|
||||
jQuery('._js_ip-filtering-open').on('click', function(e){
|
||||
e.preventDefault();
|
||||
|
||||
var title;
|
||||
switch(jQuery(this).attr('data')) {
|
||||
case "block":
|
||||
title = "Block";
|
||||
ipModal.find('input[name="type"]').attr('value', 'block');
|
||||
ipModal.find('#filterIPHelp').html("Filtering this IP under the block filter type will disallow access to the website for all modes.");
|
||||
break;
|
||||
case "maintenance":
|
||||
title = "Maintenance";
|
||||
ipModal.find('input[name="type"]').attr('value', 'maintenance');
|
||||
ipModal.find('#filterIPHelp').html("Whitelisting this IP under the maintenance filter type will allow access to the website during maintenance mode.");
|
||||
break;
|
||||
default:
|
||||
alert("Error, refresh and try again. If problem persists contact server administrator.");
|
||||
return;
|
||||
}
|
||||
title = "IP Filtering - " + title;
|
||||
|
||||
ipModal.find('.modal-title').html(title);
|
||||
|
||||
listFilteredIPs(jQuery(this).attr('data'));
|
||||
|
||||
ipModal.modal('show');
|
||||
});
|
||||
|
||||
function listFilteredIPs(type) {
|
||||
ipModal.find('._js_currently-filtered-ips').html('');
|
||||
|
||||
var requestData = {}
|
||||
requestData["type"] = type;
|
||||
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open('POST', 'api/ip/list', true);
|
||||
xhr.send(JSON.stringify(requestData));
|
||||
|
||||
xhr.onloadend = function() {
|
||||
if(xhr.status == 200) {
|
||||
if(xhr.response != undefined && xhr.response.length != 0) {
|
||||
jsonResponse = JSON.parse(xhr.response)
|
||||
console.log(xhr.response);
|
||||
jQuery.each(jsonResponse, function(k, v) {
|
||||
ipModal.find('._js_currently-filtered-ips').append("<li>"+v.ip+"</li>");
|
||||
});
|
||||
}
|
||||
else {
|
||||
ipModal.find('.modal-body').html("An error has occurred, please refresh. If problem persists contact your administrator.");
|
||||
}
|
||||
}
|
||||
else if(xhr.status == 204) {
|
||||
ipModal.find('._js_currently-filtered-ips').append("<li>No Filtered IPs Currently Exist.</li>");
|
||||
}
|
||||
else {
|
||||
if(xhr.response != undefined && xhr.response.length != 0) {
|
||||
ipModal.find('.modal-body').html(xhr.response);
|
||||
}
|
||||
else {
|
||||
ipModal.find('.modal-body').html("An error has occurred, please refresh. If problem persists contact your administrator.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -59,7 +59,18 @@
|
|||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p>Coming soon!</p>
|
||||
<form class="_js_ip-filter-form" action="api/ip/filter" method="POST">
|
||||
<div class="form-group">
|
||||
<label for="ip">Filter IP</label>
|
||||
<input name="ip" type="text" class="form-control" id="ip" aria-describedby="filterIPHelp" placeholder="127.0.0.1">
|
||||
<small id="filterIPHelp" class="form-text text-muted"></small>
|
||||
</div>
|
||||
<input type="hidden" name="type" value="">
|
||||
<button type="submit" class="btn btn-primary">Filter IP</button>
|
||||
</form>
|
||||
|
||||
<h4 class="mt-3">Currently Filtered IPs</h4>
|
||||
<ul class="_js_currently-filtered-ips"></ul>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
|
||||
|
|
@ -133,8 +144,8 @@
|
|||
IP Filtering
|
||||
</button>
|
||||
<div class="dropdown-menu" aria-labelledby="ipFilterDropdown">
|
||||
<a class="dropdown-item _js_ip-filtering-open" href="#general_ip_filter" data="general">General</a>
|
||||
<a class="dropdown-item _js_ip-filtering-open" href="#maintenance_ip_filter" data="maintenance">Maintenance Mode</a>
|
||||
<a class="dropdown-item _js_ip-filtering-open" href="#block_ip_filter" data="block">Block</a>
|
||||
<a class="dropdown-item _js_ip-filtering-open" href="#maintenance_ip_filter" data="maintenance">Maintenance</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -174,7 +185,8 @@
|
|||
<script type="text/javascript" src="assets/js/panelHandlers/log/view.js"></script>
|
||||
<script type="text/javascript" src="assets/js/panelHandlers/log/delete.js"></script>
|
||||
|
||||
<script type="text/javascript" src="assets/js/panelHandlers/security/ipFiltering.js"></script>
|
||||
<script type="text/javascript" src="assets/js/panelHandlers/security/ip_list.js"></script>
|
||||
<script type="text/javascript" src="assets/js/panelHandlers/security/filter_ip.js"></script>
|
||||
<!-- KEEP AT BOTTOM OF BODY TAGS -->
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@ func List(res http.ResponseWriter, req *http.Request, logger *log.Logger, bundle
|
|||
}
|
||||
|
||||
if len(bundles) <= 0 {
|
||||
logger.Println("no bundles :: http response returns no content")
|
||||
res.WriteHeader(http.StatusNoContent)
|
||||
return true
|
||||
}
|
||||
|
|
|
|||
59
pkg/api/ip/filter.go
Normal file
59
pkg/api/ip/filter.go
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
// Package ip is an API that deals with the blocking and unblocking of IPs on public servers
|
||||
package ip
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"log"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"github.com/Ennovar/gPanel/pkg/database"
|
||||
)
|
||||
|
||||
func Filter(res http.ResponseWriter, req *http.Request, logger *log.Logger, dir string) bool {
|
||||
if req.Method != "POST" {
|
||||
logger.Println(req.URL.Path + "::" + req.Method + "::" + strconv.Itoa(http.StatusMethodNotAllowed) + "::" + http.StatusText(http.StatusMethodNotAllowed))
|
||||
http.Error(res, http.StatusText(http.StatusMethodNotAllowed), http.StatusMethodNotAllowed)
|
||||
return false
|
||||
}
|
||||
|
||||
var blockIPRequestData struct {
|
||||
IP string `json:"ip"`
|
||||
Type string `json:"type"`
|
||||
}
|
||||
|
||||
err := json.NewDecoder(req.Body).Decode(&blockIPRequestData)
|
||||
if err != nil {
|
||||
logger.Println(req.URL.Path + "::" + err.Error())
|
||||
http.Error(res, err.Error(), http.StatusBadRequest)
|
||||
return false
|
||||
}
|
||||
|
||||
if blockIPRequestData.Type != "maintenance" && blockIPRequestData.Type != "block" {
|
||||
logger.Println(req.URL.Path + "::" + " filtered IP type is invalid")
|
||||
http.Error(res, err.Error(), http.StatusBadRequest)
|
||||
return false
|
||||
}
|
||||
|
||||
ds, err := database.Open(dir + database.DB_MAIN)
|
||||
if err != nil || ds == nil {
|
||||
logger.Println(req.URL.Path + "::" + err.Error())
|
||||
http.Error(res, err.Error(), http.StatusInternalServerError)
|
||||
return false
|
||||
}
|
||||
defer ds.Close()
|
||||
|
||||
var newIP database.Struct_Filtered_IP
|
||||
newIP.IP = blockIPRequestData.IP
|
||||
newIP.Type = blockIPRequestData.Type
|
||||
|
||||
err = ds.NewFilteredIP(&newIP)
|
||||
if err != nil {
|
||||
logger.Println(req.URL.Path + "::" + err.Error())
|
||||
http.Error(res, err.Error(), http.StatusInternalServerError)
|
||||
return false
|
||||
}
|
||||
|
||||
res.WriteHeader(http.StatusNoContent)
|
||||
return true
|
||||
}
|
||||
67
pkg/api/ip/list.go
Normal file
67
pkg/api/ip/list.go
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
package ip
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"log"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"github.com/Ennovar/gPanel/pkg/database"
|
||||
)
|
||||
|
||||
func List(res http.ResponseWriter, req *http.Request, logger *log.Logger, dir string) bool {
|
||||
if req.Method != "POST" {
|
||||
logger.Println(req.URL.Path + "::" + req.Method + "::" + strconv.Itoa(http.StatusMethodNotAllowed) + "::" + http.StatusText(http.StatusMethodNotAllowed))
|
||||
http.Error(res, http.StatusText(http.StatusMethodNotAllowed), http.StatusMethodNotAllowed)
|
||||
return false
|
||||
}
|
||||
|
||||
var listIPRequestData struct {
|
||||
Type string `json:"type"`
|
||||
}
|
||||
|
||||
err := json.NewDecoder(req.Body).Decode(&listIPRequestData)
|
||||
if err != nil {
|
||||
logger.Println(req.URL.Path + "::" + err.Error())
|
||||
http.Error(res, err.Error(), http.StatusBadRequest)
|
||||
return false
|
||||
}
|
||||
|
||||
if listIPRequestData.Type != "maintenance" && listIPRequestData.Type != "block" {
|
||||
logger.Println(req.URL.Path + "::" + " filtered IP type is invalid")
|
||||
http.Error(res, err.Error(), http.StatusBadRequest)
|
||||
return false
|
||||
}
|
||||
|
||||
ds, err := database.Open(dir + database.DB_MAIN)
|
||||
if err != nil || ds == nil {
|
||||
logger.Println(req.URL.Path + "::" + err.Error())
|
||||
http.Error(res, err.Error(), http.StatusInternalServerError)
|
||||
return false
|
||||
}
|
||||
defer ds.Close()
|
||||
|
||||
list, err := ds.GetFilteredIPs(listIPRequestData.Type)
|
||||
if err != nil {
|
||||
logger.Println(req.URL.Path + "::" + err.Error())
|
||||
http.Error(res, err.Error(), http.StatusInternalServerError)
|
||||
return false
|
||||
}
|
||||
|
||||
if len(list) > 0 {
|
||||
b, err := json.Marshal(list)
|
||||
if err != nil {
|
||||
logger.Println(req.URL.Path + "::" + err.Error())
|
||||
http.Error(res, err.Error(), http.StatusInternalServerError)
|
||||
return false
|
||||
}
|
||||
|
||||
res.WriteHeader(http.StatusOK)
|
||||
res.Write(b)
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
res.WriteHeader(http.StatusNoContent)
|
||||
return true
|
||||
}
|
||||
7
pkg/api/ip/unfilter.go
Normal file
7
pkg/api/ip/unfilter.go
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
package ip
|
||||
|
||||
import "net/http"
|
||||
|
||||
func Unfilter(res http.ResponseWriter, req *http.Request, dir string) bool {
|
||||
return true
|
||||
}
|
||||
|
|
@ -16,8 +16,18 @@ const (
|
|||
|
||||
// Bucket constants
|
||||
const (
|
||||
BUCKET_USERS = "users"
|
||||
BUCKET_PORTS = "ports"
|
||||
BUCKET_USERS = "users"
|
||||
BUCKET_PORTS = "ports"
|
||||
BUCKET_FILTERED_IPS = "filtered_ips"
|
||||
)
|
||||
|
||||
// Database Structs
|
||||
type (
|
||||
Struct_Filtered_IP struct {
|
||||
ID int `json:"id"`
|
||||
Type string `json:"type"`
|
||||
IP string `json:"ip"`
|
||||
}
|
||||
)
|
||||
|
||||
// Error codes
|
||||
|
|
@ -45,12 +55,16 @@ func Open(filepath string) (*Datastore, error) {
|
|||
// Ensure that all top-level buckets exist
|
||||
err = ds.handle.Update(func(tx *bolt.Tx) error {
|
||||
_, err := tx.CreateBucketIfNotExists([]byte(BUCKET_USERS))
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = tx.CreateBucketIfNotExists([]byte(BUCKET_PORTS))
|
||||
|
||||
_, err = tx.CreateBucketIfNotExists([]byte(BUCKET_PORTS))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = tx.CreateBucketIfNotExists([]byte(BUCKET_FILTERED_IPS))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
49
pkg/database/ip_filtering.go
Normal file
49
pkg/database/ip_filtering.go
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
package database
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"encoding/json"
|
||||
|
||||
"github.com/boltdb/bolt"
|
||||
)
|
||||
|
||||
func (ds *Datastore) NewFilteredIP(newip *Struct_Filtered_IP) error {
|
||||
return ds.handle.Update(func(tx *bolt.Tx) error {
|
||||
b := tx.Bucket([]byte(BUCKET_FILTERED_IPS))
|
||||
|
||||
id, _ := b.NextSequence()
|
||||
newip.ID = int(id)
|
||||
|
||||
buf, err := json.Marshal(newip)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
key := make([]byte, 8)
|
||||
binary.BigEndian.PutUint64(key, uint64(newip.ID))
|
||||
|
||||
return b.Put(key, buf)
|
||||
})
|
||||
}
|
||||
|
||||
func (ds *Datastore) GetFilteredIPs(iptype string) (map[int]Struct_Filtered_IP, error) {
|
||||
filtered := make(map[int]Struct_Filtered_IP)
|
||||
var holder Struct_Filtered_IP
|
||||
|
||||
ds.handle.View(func(tx *bolt.Tx) error {
|
||||
b := tx.Bucket([]byte(BUCKET_FILTERED_IPS))
|
||||
c := b.Cursor()
|
||||
|
||||
for k, v := c.First(); k != nil; k, v = c.Next() {
|
||||
json.Unmarshal(v, &holder)
|
||||
|
||||
if holder.Type == iptype {
|
||||
filtered[holder.ID] = holder
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
return filtered, nil
|
||||
}
|
||||
|
|
@ -5,6 +5,7 @@ import (
|
|||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/Ennovar/gPanel/pkg/api/ip"
|
||||
logapi "github.com/Ennovar/gPanel/pkg/api/log"
|
||||
"github.com/Ennovar/gPanel/pkg/api/server"
|
||||
"github.com/Ennovar/gPanel/pkg/api/user"
|
||||
|
|
@ -42,6 +43,10 @@ func (con *Controller) apiHandler(res http.ResponseWriter, req *http.Request) (b
|
|||
return true, logapi.Read(res, req, con.APILogger, con.Directory)
|
||||
case "/log/delete":
|
||||
return true, logapi.Truncate(res, req, con.APILogger, con.Directory)
|
||||
case "/ip/list":
|
||||
return true, ip.List(res, req, con.APILogger, con.Directory)
|
||||
case "/ip/filter":
|
||||
return true, ip.Filter(res, req, con.APILogger, con.Directory)
|
||||
default:
|
||||
return false, false
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,22 +3,35 @@
|
|||
package networking
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"net/http"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// GetClientIP returns the current client's IP as an array of bytes.
|
||||
// BUG(george-e-shaw-iv) Uses an external API
|
||||
func GetClientIP() ([]byte, error) {
|
||||
resp, err := http.Get("http://myexternalip.com/raw")
|
||||
// GetClientIP returns the current client's IP
|
||||
func GetClientIP(req *http.Request) string {
|
||||
var addr string
|
||||
regex := regexp.MustCompile(`(?i)(?:for=)([^(;|,| )]+)`)
|
||||
|
||||
if err != nil {
|
||||
return []byte{}, err
|
||||
if fwd := req.Header.Get(http.CanonicalHeaderKey("X-Forwarded-For")); fwd != "" {
|
||||
s := strings.Index(fwd, ", ")
|
||||
|
||||
if s == -1 {
|
||||
s = len(fwd)
|
||||
}
|
||||
|
||||
addr = fwd[:s]
|
||||
} else if fwd := req.Header.Get(http.CanonicalHeaderKey("X-Real-IP")); fwd != "" {
|
||||
addr = fwd
|
||||
} else if fwd := req.Header.Get(http.CanonicalHeaderKey("Forwarded")); fwd != "" {
|
||||
|
||||
if match := regex.FindStringSubmatch(fwd); len(match) > 1 {
|
||||
addr = strings.Trim(match[1], `"`)
|
||||
}
|
||||
|
||||
} else {
|
||||
addr = strings.Split(req.RemoteAddr, ":")[0]
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
buf := new(bytes.Buffer)
|
||||
buf.ReadFrom(resp.Body)
|
||||
|
||||
return buf.Bytes(), nil
|
||||
return addr
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,10 +19,9 @@ jQuery('._js_bundles-manage').on('click', function(e){
|
|||
else {
|
||||
manageBundlesModal.find('.modal-body').html("An error has occurred. Please try again. If problem persists contact server administrator.")
|
||||
}
|
||||
manageBundlesModal.modal('show');
|
||||
}
|
||||
else if(xhr.status == 204) {
|
||||
manageBundlesModal.modal('show');
|
||||
manageBundlesModal.find('.modal-body').html("<p>No bundles current exist on the server.</p>")
|
||||
}
|
||||
else {
|
||||
if(xhr.response != undefined && xhr.response.length != 0) {
|
||||
|
|
@ -31,7 +30,8 @@ jQuery('._js_bundles-manage').on('click', function(e){
|
|||
else {
|
||||
manageBundlesModal.find('.modal-body').html(xhr.status + " Error!")
|
||||
}
|
||||
manageBundlesModal.modal('show');
|
||||
}
|
||||
}
|
||||
|
||||
manageBundlesModal.modal('show');
|
||||
});
|
||||
|
|
|
|||
|
|
@ -74,9 +74,7 @@
|
|||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p>No bundles current exist on the server.</p>
|
||||
</div>
|
||||
<div class="modal-body"></div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
|
||||
</div>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue