Browse Source

Added working whitelist on web ui

tobychui 3 years ago
parent
commit
137096e114

+ 7 - 0
auth.go

@@ -93,6 +93,13 @@ func AuthSettingsInit() {
 		RequireAdmin: true,
 		RequireAdmin: true,
 	})
 	})
 
 
+	//Whitelist API
+	adminRouter.HandleFunc("/system/auth/whitelist/enable", authAgent.WhitelistManager.HandleSetWhitelistEnable)
+	adminRouter.HandleFunc("/system/auth/whitelist/list", authAgent.WhitelistManager.HandleListWhitelistedIPs)
+	adminRouter.HandleFunc("/system/auth/whitelist/set", authAgent.WhitelistManager.HandleAddWhitelistedIP)
+	adminRouter.HandleFunc("/system/auth/whitelist/unset", authAgent.WhitelistManager.HandleRemoveWhitelistedIP)
+
+	//Blacklist API
 	adminRouter.HandleFunc("/system/auth/blacklist/enable", authAgent.BlacklistManager.HandleSetBlacklistEnable)
 	adminRouter.HandleFunc("/system/auth/blacklist/enable", authAgent.BlacklistManager.HandleSetBlacklistEnable)
 	adminRouter.HandleFunc("/system/auth/blacklist/list", authAgent.BlacklistManager.HandleListBannedIPs)
 	adminRouter.HandleFunc("/system/auth/blacklist/list", authAgent.BlacklistManager.HandleListBannedIPs)
 	adminRouter.HandleFunc("/system/auth/blacklist/ban", authAgent.BlacklistManager.HandleAddBannedIP)
 	adminRouter.HandleFunc("/system/auth/blacklist/ban", authAgent.BlacklistManager.HandleAddBannedIP)

+ 33 - 0
console.go

@@ -167,6 +167,39 @@ func consoleCommandHandler(input string) string {
 			fmt.Println(ssRouter.RunningSubService)
 			fmt.Println(ssRouter.RunningSubService)
 			return "OK"
 			return "OK"
 		}
 		}
+	} else if len(chunk) > 0 && chunk[0] == "access" {
+		//Handle emergency situation where the user is blocked by himself
+		if matchSubfix(chunk, []string{"access", "whitelist", "disable"}, 3, "") {
+			//Disable whitelist
+			authAgent.WhitelistManager.SetWhitelistEnabled(false)
+			return "Whitelist Disabled"
+		} else if matchSubfix(chunk, []string{"access", "whitelist", "enable"}, 3, "") {
+			//Enable whitelist
+			authAgent.WhitelistManager.SetWhitelistEnabled(true)
+			return "Whitelist Enabled"
+		} else if matchSubfix(chunk, []string{"access", "whitelist", "add"}, 4, "access whitelist add {ip_range}") {
+			err = authAgent.WhitelistManager.SetWhitelist(chunk[3])
+			if err != nil {
+				return err.Error()
+			}
+			return "OK"
+		} else if matchSubfix(chunk, []string{"access", "whitelist", "del"}, 4, "access whitelist del {ip_range}") {
+			err = authAgent.WhitelistManager.UnsetWhitelist(chunk[3])
+			if err != nil {
+				return err.Error()
+			}
+			return "OK"
+		} else if matchSubfix(chunk, []string{"access", "blacklist", "enable"}, 3, "") {
+			//Enable blacklist
+			authAgent.WhitelistManager.SetWhitelistEnabled(true)
+			return "Blacklist Enabled"
+		} else if matchSubfix(chunk, []string{"access", "blacklist", "disable"}, 3, "") {
+			//Disable blacklist
+			authAgent.BlacklistManager.SetBlacklistEnabled(false)
+			return "Blacklist Disabled"
+		} else {
+			return "[Whitelist / Blacklist Console Control API] \nUsage: access {whitelist/blacklist} {action} {data}"
+		}
 	} else if len(chunk) == 1 && chunk[0] == "stop" {
 	} else if len(chunk) == 1 && chunk[0] == "stop" {
 		//Stopping the server
 		//Stopping the server
 		fmt.Println("Shutting down aroz online system by terminal request")
 		fmt.Println("Shutting down aroz online system by terminal request")

+ 1 - 0
mod/auth/accesscontrol/accesscontrol.go

@@ -0,0 +1 @@
+package accesscontrol

+ 109 - 0
mod/auth/accesscontrol/blacklist/blacklist.go

@@ -0,0 +1,109 @@
+package blacklist
+
+import (
+	"errors"
+	"log"
+	"strings"
+
+	"imuslab.com/arozos/mod/auth/accesscontrol"
+	db "imuslab.com/arozos/mod/database"
+)
+
+/*
+
+	ArozOS Blacklist Module
+	Author: tobychui
+
+	This module record the IP blacklist of users trying to enter the
+	system without permission
+
+*/
+
+type BlackList struct {
+	Enabled  bool
+	database *db.Database
+}
+
+func NewBlacklistManager(sysdb *db.Database) *BlackList {
+	sysdb.NewTable("ipblacklist")
+
+	blacklistEnabled := false
+	if sysdb.KeyExists("ipblacklist", "enable") {
+		err := sysdb.Read("ipblacklist", "enable", &blacklistEnabled)
+		if err != nil {
+			log.Println("[Auth/Blacklist] Unable to load previous enable state from database. Using default.")
+		}
+	}
+
+	return &BlackList{
+		Enabled:  blacklistEnabled,
+		database: sysdb,
+	}
+}
+
+//Check if a given IP is banned
+func (bl *BlackList) IsBanned(ip string) bool {
+	if bl.Enabled == false {
+		return false
+	}
+	if bl.database.KeyExists("ipblacklist", ip) {
+		return true
+	}
+
+	//The ip might be inside as a range. Do a range search.
+	//Need optimization, current implementation is O(N)
+	for _, thisIpRange := range bl.ListBannedIpRanges() {
+		if accesscontrol.IpInRange(ip, thisIpRange) {
+			return true
+		}
+	}
+	return false
+}
+
+func (bl *BlackList) ListBannedIpRanges() []string {
+	entries, err := bl.database.ListTable("ipblacklist")
+	if err != nil {
+		return []string{}
+	}
+	results := []string{}
+	for _, keypairs := range entries {
+		thisIpRange := keypairs[0]
+		if string(thisIpRange) == "enable" || accesscontrol.ValidateIpRange(string(thisIpRange)) != nil {
+			//Reserved key field
+			continue
+		}
+		results = append(results, string(thisIpRange))
+	}
+	return results
+}
+
+//Set the ban state of a ip or ip range
+func (bl *BlackList) Ban(ipRange string) error {
+	//Check if the IP range is correct
+	err := accesscontrol.ValidateIpRange(ipRange)
+	if err != nil {
+		return err
+	}
+
+	//Push it to the ban list
+	ipRange = strings.TrimSpace(ipRange)
+	ipRange = strings.ReplaceAll(ipRange, " ", "")
+	return bl.database.Write("ipblacklist", ipRange, true)
+}
+
+//Unban an IP or IP range
+func (bl *BlackList) UnBan(ipRange string) error {
+	//Check if the IP range is correct
+	err := accesscontrol.ValidateIpRange(ipRange)
+	if err != nil {
+		return err
+	}
+
+	//Check if the ip range is banned
+	if !bl.database.KeyExists("ipblacklist", ipRange) {
+		return errors.New("invalid IP range given")
+	}
+
+	//Ip range exists, remove it from database
+	return bl.database.Delete("ipblacklist", ipRange)
+}

+ 14 - 12
mod/auth/blacklist/blacklist_test.go → mod/auth/accesscontrol/blacklist/blacklist_test.go

@@ -2,12 +2,14 @@ package blacklist
 
 
 import (
 import (
 	"testing"
 	"testing"
+
+	"imuslab.com/arozos/mod/auth/accesscontrol"
 )
 )
 
 
 func TestIpRangeBreakdown(t *testing.T) {
 func TestIpRangeBreakdown(t *testing.T) {
 	ipRange := "192.168.1.155 - 192.168.1.158"
 	ipRange := "192.168.1.155 - 192.168.1.158"
 	sol := []string{"192.168.1.155", "192.168.1.156", "192.168.1.157", "192.168.1.158"}
 	sol := []string{"192.168.1.155", "192.168.1.156", "192.168.1.157", "192.168.1.158"}
-	breakdown := breakdownIpRange(ipRange)
+	breakdown := accesscontrol.BreakdownIpRange(ipRange)
 	if len(sol) != len(breakdown) {
 	if len(sol) != len(breakdown) {
 		t.Fatal("IP range breakdown length incorrect, result: ", breakdown)
 		t.Fatal("IP range breakdown length incorrect, result: ", breakdown)
 	} else {
 	} else {
@@ -16,17 +18,17 @@ func TestIpRangeBreakdown(t *testing.T) {
 }
 }
 
 
 func TestIpInRange(t *testing.T) {
 func TestIpInRange(t *testing.T) {
-	r := ipInRange("192.168.1.128", "192.168.1.100 - 192.168.1.200")
+	r := accesscontrol.IpInRange("192.168.1.128", "192.168.1.100 - 192.168.1.200")
 	if r == false {
 	if r == false {
 		t.Fatal("Correct IP in range reported as error")
 		t.Fatal("Correct IP in range reported as error")
 	}
 	}
 
 
-	r = ipInRange("192.168.1.128", "192.168.1.128 ")
+	r = accesscontrol.IpInRange("192.168.1.128", "192.168.1.128 ")
 	if r == false {
 	if r == false {
 		t.Fatal("Correct IP in range reported as error")
 		t.Fatal("Correct IP in range reported as error")
 	}
 	}
 
 
-	r = ipInRange("192.168.1.128", "192.168.1.1 - 192.168.1.100")
+	r = accesscontrol.IpInRange("192.168.1.128", "192.168.1.1 - 192.168.1.100")
 	if r == true {
 	if r == true {
 		t.Fatal("Invalid IP in range reported as correct")
 		t.Fatal("Invalid IP in range reported as correct")
 	}
 	}
@@ -34,44 +36,44 @@ func TestIpInRange(t *testing.T) {
 }
 }
 
 
 func TestSingleIP(t *testing.T) {
 func TestSingleIP(t *testing.T) {
-	err := validateIpRange("192.168.1.128")
+	err := accesscontrol.ValidateIpRange("192.168.1.128")
 	if err != nil {
 	if err != nil {
 		t.Fatal("Correct IP range reported as error", err)
 		t.Fatal("Correct IP range reported as error", err)
 	}
 	}
 
 
-	err = validateIpRange("192.168.1.asd")
+	err = accesscontrol.ValidateIpRange("192.168.1.asd")
 	if err == nil {
 	if err == nil {
 		t.Fatal("Invalid ip reported as correct", err)
 		t.Fatal("Invalid ip reported as correct", err)
 	}
 	}
 
 
-	err = validateIpRange("192.168.1.100.123.234")
+	err = accesscontrol.ValidateIpRange("192.168.1.100.123.234")
 	if err == nil {
 	if err == nil {
 		t.Fatal("Invalid ip reported as correct", err)
 		t.Fatal("Invalid ip reported as correct", err)
 	}
 	}
 
 
 }
 }
 func TestIPRange(t *testing.T) {
 func TestIPRange(t *testing.T) {
-	err := validateIpRange("192.168.1.150 - 192.168.1.250")
+	err := accesscontrol.ValidateIpRange("192.168.1.150 - 192.168.1.250")
 	if err != nil {
 	if err != nil {
 		t.Fatal("Correct IP range reported as error", err)
 		t.Fatal("Correct IP range reported as error", err)
 	}
 	}
 
 
-	err = validateIpRange("192.168.1.1 - 192.168.1.100")
+	err = accesscontrol.ValidateIpRange("192.168.1.1 - 192.168.1.100")
 	if err != nil {
 	if err != nil {
 		t.Fatal("Correct IP range reported as error", err)
 		t.Fatal("Correct IP range reported as error", err)
 	}
 	}
 
 
-	err = validateIpRange("192.168.1.255 - 192.168.1.250")
+	err = accesscontrol.ValidateIpRange("192.168.1.255 - 192.168.1.250")
 	if err == nil {
 	if err == nil {
 		t.Fatal("Invalid correct resp on starting ip > ending ip", err)
 		t.Fatal("Invalid correct resp on starting ip > ending ip", err)
 	}
 	}
 
 
-	err = validateIpRange("192.168.1.120 -192.168.2.100")
+	err = accesscontrol.ValidateIpRange("192.168.1.120 -192.168.2.100")
 	if err == nil {
 	if err == nil {
 		t.Fatal("Invalid ip range reported as correct", err)
 		t.Fatal("Invalid ip range reported as correct", err)
 	}
 	}
 
 
-	err = validateIpRange("d037:b377:039a:b621:145b:0d10:3d38:982f - 4fe9:1561:c37c:1f66:f696:948d:c452:73a3")
+	err = accesscontrol.ValidateIpRange("d037:b377:039a:b621:145b:0d10:3d38:982f - 4fe9:1561:c37c:1f66:f696:948d:c452:73a3")
 	if err == nil {
 	if err == nil {
 		t.Fatal("Not supported ip range reported as correct", err)
 		t.Fatal("Not supported ip range reported as correct", err)
 	}
 	}

+ 11 - 4
mod/auth/blacklist/handler.go → mod/auth/accesscontrol/blacklist/handler.go

@@ -55,18 +55,25 @@ func (bl *BlackList) HandleSetBlacklistEnable(w http.ResponseWriter, r *http.Req
 		return
 		return
 	} else {
 	} else {
 		if strings.ToLower(enableMode) == "true" {
 		if strings.ToLower(enableMode) == "true" {
-			bl.Enabled = true
-			bl.database.Write("ipblacklist", "enable", true)
+			bl.SetBlacklistEnabled(true)
 			common.SendOK(w)
 			common.SendOK(w)
 		} else if strings.ToLower(enableMode) == "false" {
 		} else if strings.ToLower(enableMode) == "false" {
-			bl.Enabled = false
-			bl.database.Write("ipblacklist", "enable", false)
+			bl.SetBlacklistEnabled(false)
 			common.SendOK(w)
 			common.SendOK(w)
 		} else {
 		} else {
 			common.SendErrorResponse(w, "Invalid mode given")
 			common.SendErrorResponse(w, "Invalid mode given")
 		}
 		}
 	}
 	}
 }
 }
+func (bl *BlackList) SetBlacklistEnabled(enabled bool) {
+	if enabled {
+		bl.Enabled = true
+		bl.database.Write("ipblacklist", "enable", true)
+	} else {
+		bl.Enabled = false
+		bl.database.Write("ipblacklist", "enable", false)
+	}
+}
 
 
 func (bl *BlackList) HandleListBannedIPs(w http.ResponseWriter, r *http.Request) {
 func (bl *BlackList) HandleListBannedIPs(w http.ResponseWriter, r *http.Request) {
 	bannedIpRanges := bl.ListBannedIpRanges()
 	bannedIpRanges := bl.ListBannedIpRanges()

+ 5 - 107
mod/auth/blacklist/blacklist.go → mod/auth/accesscontrol/utils.go

@@ -1,119 +1,17 @@
-package blacklist
+package accesscontrol
 
 
 import (
 import (
 	"bytes"
 	"bytes"
 	"errors"
 	"errors"
-	"log"
 	"net"
 	"net"
 	"strconv"
 	"strconv"
 	"strings"
 	"strings"
-
-	db "imuslab.com/arozos/mod/database"
 )
 )
 
 
-/*
-
-	ArozOS Blacklist Module
-	Author: tobychui
-
-	This module record the IP blacklist of users trying to enter the
-	system without permission
-
-*/
-
-type BlackList struct {
-	Enabled  bool
-	database *db.Database
-}
-
-func NewBlacklistManager(sysdb *db.Database) *BlackList {
-	sysdb.NewTable("ipblacklist")
-
-	blacklistEnabled := false
-	if sysdb.KeyExists("ipblacklist", "enable") {
-		err := sysdb.Read("ipblacklist", "enable", &blacklistEnabled)
-		if err != nil {
-			log.Println("[Auth/Blacklist] Unable to load previous enable state from database. Using default.")
-		}
-	}
-
-	return &BlackList{
-		Enabled:  blacklistEnabled,
-		database: sysdb,
-	}
-}
-
-//Check if a given IP is banned
-func (bl *BlackList) IsBanned(ip string) bool {
-	if bl.Enabled == false {
-		return false
-	}
-	if bl.database.KeyExists("ipblacklist", ip) {
-		return true
-	}
-
-	//The ip might be inside as a range. Do a range search.
-	//Need optimization, current implementation is O(N)
-	for _, thisIpRange := range bl.ListBannedIpRanges() {
-		if ipInRange(ip, thisIpRange) {
-			return true
-		}
-	}
-	return false
-}
-
-func (bl *BlackList) ListBannedIpRanges() []string {
-	entries, err := bl.database.ListTable("ipblacklist")
-	if err != nil {
-		return []string{}
-	}
-	results := []string{}
-	for _, keypairs := range entries {
-		thisIpRange := keypairs[0]
-		if string(thisIpRange) == "enable" || validateIpRange(string(thisIpRange)) != nil {
-			//Reserved key field
-			continue
-		}
-		results = append(results, string(thisIpRange))
-	}
-	return results
-}
-
-//Set the ban state of a ip or ip range
-func (bl *BlackList) Ban(ipRange string) error {
-	//Check if the IP range is correct
-	err := validateIpRange(ipRange)
-	if err != nil {
-		return err
-	}
-
-	//Push it to the ban list
-	ipRange = strings.TrimSpace(ipRange)
-	ipRange = strings.ReplaceAll(ipRange, " ", "")
-	return bl.database.Write("ipblacklist", ipRange, true)
-}
-
-//Unban an IP or IP range
-func (bl *BlackList) UnBan(ipRange string) error {
-	//Check if the IP range is correct
-	err := validateIpRange(ipRange)
-	if err != nil {
-		return err
-	}
-
-	//Check if the ip range is banned
-	if !bl.database.KeyExists("ipblacklist", ipRange) {
-		return errors.New("invalid IP range given")
-	}
-
-	//Ip range exists, remove it from database
-	return bl.database.Delete("ipblacklist", ipRange)
-}
-
 //Break an ip range text into independent ip strings
 //Break an ip range text into independent ip strings
-func breakdownIpRange(ipRange string) []string {
+func BreakdownIpRange(ipRange string) []string {
 	ipRange = strings.ReplaceAll(ipRange, " ", "")
 	ipRange = strings.ReplaceAll(ipRange, " ", "")
-	err := validateIpRange(ipRange)
+	err := ValidateIpRange(ipRange)
 	if err != nil {
 	if err != nil {
 		return []string{}
 		return []string{}
 	}
 	}
@@ -149,7 +47,7 @@ func breakdownIpRange(ipRange string) []string {
 }
 }
 
 
 //Check if an given ip in the given range
 //Check if an given ip in the given range
-func ipInRange(ip string, ipRange string) bool {
+func IpInRange(ip string, ipRange string) bool {
 	ip = strings.TrimSpace(ip)
 	ip = strings.TrimSpace(ip)
 	ipRange = strings.ReplaceAll(ipRange, " ", "")
 	ipRange = strings.ReplaceAll(ipRange, " ", "")
 	if ip == ipRange {
 	if ip == ipRange {
@@ -185,7 +83,7 @@ func ipInRange(ip string, ipRange string) bool {
 }
 }
 
 
 //Check if the given IP Range string is actually an IP range
 //Check if the given IP Range string is actually an IP range
-func validateIpRange(ipRange string) error {
+func ValidateIpRange(ipRange string) error {
 	ipRange = strings.TrimSpace(ipRange)
 	ipRange = strings.TrimSpace(ipRange)
 	ipRange = strings.ReplaceAll(ipRange, " ", "")
 	ipRange = strings.ReplaceAll(ipRange, " ", "")
 	if strings.Contains(ipRange, "-") {
 	if strings.Contains(ipRange, "-") {

+ 82 - 0
mod/auth/accesscontrol/whitelist/handler.go

@@ -0,0 +1,82 @@
+package whitelist
+
+import (
+	"encoding/json"
+	"net/http"
+	"strings"
+
+	"imuslab.com/arozos/mod/common"
+	"imuslab.com/arozos/mod/network"
+)
+
+func (wl *WhiteList) HandleAddWhitelistedIP(w http.ResponseWriter, r *http.Request) {
+	ipRange, err := common.Mv(r, "iprange", true)
+	if err != nil {
+		common.SendErrorResponse(w, "Invalid ip range given")
+		return
+	}
+
+	err = wl.SetWhitelist(ipRange)
+	if err != nil {
+		common.SendErrorResponse(w, err.Error())
+		return
+	}
+
+	common.SendOK(w)
+}
+
+func (wl *WhiteList) HandleRemoveWhitelistedIP(w http.ResponseWriter, r *http.Request) {
+	ipRange, err := common.Mv(r, "iprange", true)
+	if err != nil {
+		common.SendErrorResponse(w, "Invalid ip range given")
+		return
+	}
+
+	err = wl.UnsetWhitelist(ipRange)
+	if err != nil {
+		common.SendErrorResponse(w, err.Error())
+		return
+	}
+
+	common.SendOK(w)
+}
+
+func (wl *WhiteList) HandleSetWhitelistEnable(w http.ResponseWriter, r *http.Request) {
+	enableMode, _ := common.Mv(r, "enable", true)
+	if enableMode == "" {
+		//Get the current whitelist status
+		js, _ := json.Marshal(wl.Enabled)
+		common.SendJSONResponse(w, string(js))
+		return
+	} else {
+		if strings.ToLower(enableMode) == "true" {
+			wl.SetWhitelistEnabled(true)
+			common.SendOK(w)
+		} else if strings.ToLower(enableMode) == "false" {
+			wl.SetWhitelistEnabled(false)
+			common.SendOK(w)
+		} else {
+			common.SendErrorResponse(w, "Invalid mode given")
+		}
+	}
+}
+
+func (wl *WhiteList) HandleListWhitelistedIPs(w http.ResponseWriter, r *http.Request) {
+	bannedIpRanges := wl.ListWhitelistedIpRanges()
+	js, _ := json.Marshal(bannedIpRanges)
+	common.SendJSONResponse(w, string(js))
+}
+
+func (wl *WhiteList) CheckIsWhitelistedByRequest(r *http.Request) bool {
+	if wl.Enabled == false {
+		//Whitelist not enabled. Always return is whitelisted
+		return true
+	}
+	//Get the IP address from the request header
+	requestIP, err := network.GetIpFromRequest(r)
+	if err != nil {
+		return false
+	}
+
+	return wl.IsWhitelisted(requestIP)
+}

+ 119 - 0
mod/auth/accesscontrol/whitelist/whitelist.go

@@ -0,0 +1,119 @@
+package whitelist
+
+import (
+	"errors"
+	"log"
+	"strings"
+
+	"imuslab.com/arozos/mod/auth/accesscontrol"
+	"imuslab.com/arozos/mod/database"
+)
+
+/*
+	Whitelist
+
+*/
+
+type WhiteList struct {
+	database *database.Database
+	Enabled  bool
+}
+
+func NewWhitelistManager(sysdb *database.Database) *WhiteList {
+	sysdb.NewTable("ipwhitelist")
+
+	whitelistEnabled := false
+	if sysdb.KeyExists("ipwhitelist", "enable") {
+		err := sysdb.Read("ipwhitelist", "enable", &whitelistEnabled)
+		if err != nil {
+			log.Println("[Auth/Whitelist] Unable to load previous enable state from database. Using default.")
+		}
+	}
+
+	return &WhiteList{
+		database: sysdb,
+		Enabled:  whitelistEnabled,
+	}
+}
+
+func (wl *WhiteList) SetWhitelistEnabled(enable bool) {
+	if enable {
+		wl.Enabled = true
+		wl.database.Write("ipwhitelist", "enable", true)
+	} else {
+		wl.Enabled = false
+		wl.database.Write("ipwhitelist", "enable", false)
+	}
+}
+
+func (wl *WhiteList) IsWhitelisted(ip string) bool {
+	//Check if whitelist is enabled
+	if wl.Enabled == false {
+		return true
+	}
+
+	//Check if this is reserved IP address
+	if ip == "127.0.0.1" || ip == "localhost" {
+		return true
+	}
+
+	//Check if this particular ip is whitelisted
+	if wl.database.KeyExists("ipwhitelist", ip) {
+		return true
+	}
+
+	//The ip might be inside as a range. Do a range search.
+	//Need optimization, current implementation is O(N)
+	for _, thisIpRange := range wl.ListWhitelistedIpRanges() {
+		if accesscontrol.IpInRange(ip, thisIpRange) {
+			return true
+		}
+	}
+	return false
+}
+
+func (wl *WhiteList) ListWhitelistedIpRanges() []string {
+	entries, err := wl.database.ListTable("ipwhitelist")
+	if err != nil {
+		return []string{}
+	}
+	results := []string{"127.0.0.1"}
+	for _, keypairs := range entries {
+		thisIpRange := keypairs[0]
+		if string(thisIpRange) == "enable" || accesscontrol.ValidateIpRange(string(thisIpRange)) != nil {
+			//Reserved key field
+			continue
+		}
+		results = append(results, string(thisIpRange))
+	}
+	return results
+}
+
+func (wl *WhiteList) SetWhitelist(ipRange string) error {
+	//Check if the IP range is correct
+	err := accesscontrol.ValidateIpRange(ipRange)
+	if err != nil {
+		return err
+	}
+
+	//Push it to the ban list
+	ipRange = strings.TrimSpace(ipRange)
+	ipRange = strings.ReplaceAll(ipRange, " ", "")
+	return wl.database.Write("ipwhitelist", ipRange, true)
+}
+
+func (wl *WhiteList) UnsetWhitelist(ipRange string) error {
+	//Check if the IP range is correct
+	err := accesscontrol.ValidateIpRange(ipRange)
+	if err != nil {
+		return err
+	}
+
+	//Check if the ip range is banned
+	if !wl.database.KeyExists("ipwhitelist", ipRange) {
+		return errors.New("invalid IP range given")
+	}
+
+	//Ip range exists, remove it from database
+	return wl.database.Delete("ipwhitelist", ipRange)
+}

+ 16 - 4
mod/auth/auth.go

@@ -32,8 +32,9 @@ import (
 
 
 	"github.com/gorilla/sessions"
 	"github.com/gorilla/sessions"
 
 
+	"imuslab.com/arozos/mod/auth/accesscontrol/blacklist"
+	"imuslab.com/arozos/mod/auth/accesscontrol/whitelist"
 	"imuslab.com/arozos/mod/auth/authlogger"
 	"imuslab.com/arozos/mod/auth/authlogger"
-	"imuslab.com/arozos/mod/auth/blacklist"
 	db "imuslab.com/arozos/mod/database"
 	db "imuslab.com/arozos/mod/database"
 )
 )
 
 
@@ -54,7 +55,8 @@ type AuthAgent struct {
 	AllowAutoLogin  bool
 	AllowAutoLogin  bool
 	autoLoginTokens []*AutoLoginToken
 	autoLoginTokens []*AutoLoginToken
 
 
-	//IP Blacklist manager
+	//IPLists manager
+	WhitelistManager *whitelist.WhiteList
 	BlacklistManager *blacklist.BlackList
 	BlacklistManager *blacklist.BlackList
 
 
 	//Logger
 	//Logger
@@ -82,6 +84,9 @@ func NewAuthenticationAgent(sessionName string, key []byte, sysdb *db.Database,
 	ticker := time.NewTicker(300 * time.Second)
 	ticker := time.NewTicker(300 * time.Second)
 	done := make(chan bool)
 	done := make(chan bool)
 
 
+	//Create a new whitelist manager
+	thisWhitelistManager := whitelist.NewWhitelistManager(sysdb)
+
 	//Create a new blacklist manager
 	//Create a new blacklist manager
 	thisBlacklistManager := blacklist.NewBlacklistManager(sysdb)
 	thisBlacklistManager := blacklist.NewBlacklistManager(sysdb)
 
 
@@ -107,6 +112,7 @@ func NewAuthenticationAgent(sessionName string, key []byte, sysdb *db.Database,
 		autoLoginTokens: []*AutoLoginToken{},
 		autoLoginTokens: []*AutoLoginToken{},
 
 
 		//Blacklist management
 		//Blacklist management
+		WhitelistManager: thisWhitelistManager,
 		BlacklistManager: thisBlacklistManager,
 		BlacklistManager: thisBlacklistManager,
 		Logger:           newLogger,
 		Logger:           newLogger,
 	}
 	}
@@ -228,10 +234,16 @@ func (a *AuthAgent) ValidateUsernameAndPasswordWithReason(username string, passw
 
 
 //Validate the user request for login
 //Validate the user request for login
 func (a *AuthAgent) ValidateLoginRequest(w http.ResponseWriter, r *http.Request) (bool, error) {
 func (a *AuthAgent) ValidateLoginRequest(w http.ResponseWriter, r *http.Request) (bool, error) {
+	//Check if the account is whitelisted
+	if a.WhitelistManager.Enabled && !a.WhitelistManager.CheckIsWhitelistedByRequest(r) {
+		//Whitelist enabled but this IP is not whitelisted
+		return false, errors.New("Your IP is not whitelisted on this host")
+	}
+
 	//Check if the account is banned
 	//Check if the account is banned
-	if a.BlacklistManager.CheckIsBannedByRequest(r) {
+	if a.BlacklistManager.Enabled && a.BlacklistManager.CheckIsBannedByRequest(r) {
 		//This user is banned
 		//This user is banned
-		return false, errors.New("This IP is banned")
+		return false, errors.New("Your IP is banned by this host")
 	}
 	}
 	return true, nil
 	return true, nil
 }
 }

+ 0 - 9
web/Music/index.html

@@ -563,15 +563,6 @@
 		searchModeEnabled = false;
 		searchModeEnabled = false;
 	}
 	}
 
 
-	/*
-	$("#searchInputBar").on("keypress",function(e){
-		if(e.keyCode == 13){
-			//Enter pressed. start searching
-			searchSong();
-		}
-	});
-	*/
-
 	document.getElementById("searchInputBar").addEventListener("keypress", function(event){
 	document.getElementById("searchInputBar").addEventListener("keypress", function(event){
 		console.log(event, event.keyCode);
 		console.log(event, event.keyCode);
 		if(event.keyCode == 13){
 		if(event.keyCode == 13){

+ 140 - 12
web/SystemAO/security/accesscontrol.html

@@ -39,10 +39,36 @@
         <div>
         <div>
             <h3 class="ui header">
             <h3 class="ui header">
                 Access Control
                 Access Control
-                <div class="sub header">Manage IPs from accessing this host</div>
+                <div class="sub header">Manage IPs from logging into this host</div>
             </h3>
             </h3>
             <div class="ui divider"></div>
             <div class="ui divider"></div>
             <h3><i class="ui green checkmark icon"></i> Whitelist</h3>
             <h3><i class="ui green checkmark icon"></i> Whitelist</h3>
+            <div class="ui toggle checkbox">
+                <input type="checkbox" id="enableWhiteList" onchange="">
+                <label>Enable Whitelist Filtering</label>
+            </div>
+            <div class="ui inverted green segment" id="whitelistUpdateFeedback" style="display:none;">
+                <i class="ui checkmark icon"></i> Whitelist Status Updated
+            </div>
+
+            <div class="ui basic segment">
+                <p>Add or Remove new whitelisted IP range</p>
+                <div class="ui action fluid input">
+                    <input type="text" id="whitelistIpRange" placeholder="192.168.1.100 - 192.168.1.250">
+                    <button class="ui green button" onclick="whitelistIpRange();"><i class="ui checkmark icon"></i> Add</button>
+                </div>
+
+                <table class="ui celled table">
+                    <thead>
+                        <tr><th>IP Range</th>
+                        <th>Remove</th>
+                    </tr></thead>
+                    <tbody id="whitelistTable">
+
+                    </tbody>
+                </table>
+            </div>
+
 
 
             <div class="ui divider"></div>
             <div class="ui divider"></div>
             <h3><i class="ui red remove icon"></i> Blacklist</h3>
             <h3><i class="ui red remove icon"></i> Blacklist</h3>
@@ -51,19 +77,10 @@
                 <label>Enable Blacklist Filtering</label>
                 <label>Enable Blacklist Filtering</label>
             </div>
             </div>
             <div class="ui inverted green segment" id="blacklistUpdateFeedback" style="display:none;">
             <div class="ui inverted green segment" id="blacklistUpdateFeedback" style="display:none;">
-                <i class="ui checkmark icon"></i> Status Updated
+                <i class="ui checkmark icon"></i> Blacklist Status Updated
             </div>
             </div>
             <div class="ui basic segment">
             <div class="ui basic segment">
-                <div class="ui grey message">
-                    <p>Block certain IP or IP range from logging into the system. Syntax Examples:</p>
-                    <div class="ui bulleted list">
-                        <div class="item">192.168.1.100</div>
-                        <div class="item">123.36.53.100</div>
-                        <div class="item">192.168.0.100 - 192.168.0.250</div>
-                    </div>
-                </div>
-
-                <p>Add or Edit new banned IP range</p>
+                <p>Add or Remove new banned IP range</p>
                 <div class="ui action fluid input">
                 <div class="ui action fluid input">
                     <input type="text" id="blacklistIpRange" placeholder="192.168.1.100 - 192.168.1.250">
                     <input type="text" id="blacklistIpRange" placeholder="192.168.1.100 - 192.168.1.250">
                     <button class="ui red button" onclick="blacklistIpRange();"><i class="ui lock icon"></i> Ban</button>
                     <button class="ui red button" onclick="blacklistIpRange();"><i class="ui lock icon"></i> Ban</button>
@@ -85,6 +102,17 @@
             <div class="ui divider"></div>
             <div class="ui divider"></div>
             <h3>Regional Block</h3>
             <h3>Regional Block</h3>
 
 
+
+            <div class="ui divider"></div>
+            <div class="ui grey message">
+                <p><i class="ui info circle icon"></i> For Whitelist and Blacklist, you can enter either a single IP or an IP range. IP range syntax examples as follows.</p>
+                <div class="ui bulleted list">
+                    <div class="item">192.168.1.100</div>
+                    <div class="item">123.36.53.100</div>
+                    <div class="item">192.168.0.100 - 192.168.0.250</div>
+                </div>
+            </div>
+            <br><br>
         </div>
         </div>
     
     
     <script>
     <script>
@@ -92,6 +120,106 @@
         var preloading = true;
         var preloading = true;
         $(".checkbox").checkbox();
         $(".checkbox").checkbox();
         initBlacklist();
         initBlacklist();
+        initWhiteList();
+
+        /*
+            Whitelist Related
+        */
+
+        function initWhiteList(){
+            //Get the whitelist enable state
+            $.get("../../system/auth/whitelist/enable", function(data){
+                if (data == true){
+                    //Whitelist is enabled
+                    $("#enableWhiteList").parent().checkbox("set checked");
+                }else{
+                    $("#enableWhiteList").parent().checkbox("set unchecked");
+                }
+
+                $("#enableWhiteList").on("change", function(){
+                    //Toggle enable
+                    $.ajax({
+                        url: "../../system/auth/whitelist/enable",
+                        method: "POST",
+                        data: {enable: this.checked},
+                        success: function(data){
+                            $("#whitelistUpdateFeedback").stop().finish().slideDown("fast").delay(3000).slideUp("fast");
+                        }
+                    })
+                })
+               
+            });
+
+            //Get the whitelist table
+            $("#whitelistTable").html(`<tr>
+                <td colspan="3"><i class="loading spinner icon"></i> Loading</td>
+            </tr>`);
+            $.get("../../system/auth/whitelist/list", function(data){
+                $("#whitelistTable").html('');
+                data.forEach(entry => {
+                    //Strip out all space from record
+                    displayEntry = entry.split(" ").join("");
+
+                    //Check if this is reserved ip range
+                    var enableRemove = true;
+                    if (entry == "127.0.0.1"){
+                        enableRemove = false;
+                    }
+
+                    var removeButtonClass = ""
+                    if (!enableRemove){
+                        removeButtonClass = "disabled";
+                    }
+
+                    $("#whitelistTable").append(`<tr>
+                    <td>${displayEntry}</td>
+                    <td><button class="ui basic red ${removeButtonClass} icon button" onclick="removeWhitelistforIpRange(this);" range="${entry}"><i class="ui white remove icon"></i></button></td>
+                  </tr>`);
+                })
+
+                if (data.length == 0){
+                    $("#whitelistTable").html(`<tr>
+                        <td colspan="3"><i class="remove icon"></i> No Whitelisted IPs</td>
+                    </tr>`);
+                }
+            });
+        }
+
+        function whitelistIpRange(){
+            var targetIP = $("#whitelistIpRange").val();
+            $.ajax({
+                url: "../../system/auth/whitelist/set",
+                method: "POST",
+                data: {iprange: targetIP},
+                success: function(data){
+                    if (data.error != undefined){
+                        alert(data.error);
+                    }else{
+                        $("#whitelistIpRange").val('')
+                        initWhiteList();
+                    }
+                    
+                }
+            });
+        }
+
+        function removeWhitelistforIpRange(object){
+            var unbanIpRange = $(object).attr("range");
+            $.ajax({
+                url: "../../system/auth/whitelist/unset",
+                method: "POST",
+                data: {iprange: unbanIpRange},
+                success: function(data){
+                    if (data.error != undefined){
+                        alert(data.error);
+                    }else{
+                        $("#whitelistIpRange").val('')
+                        initWhiteList();
+                    }
+                    
+                }
+            });
+        }
 
 
         /*
         /*