Skip to content

Commit

Permalink
Merge branch 'release' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
RaspberryTech01 committed Oct 17, 2021
2 parents 741e656 + dcd1c5f commit 50fb876
Show file tree
Hide file tree
Showing 18 changed files with 577 additions and 263 deletions.
29 changes: 28 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ The SQLite database contains tables which store information such as generated an
- [3.2 Removing keys](#removing-keys)
- [3.3 Enabling keys](#enabling-keys)
- [3.4 Disabling keys](#disabling-keys)
- [3.5 Editing subscriptions](#editing-subscriptions )

**[4. Debugging](#debugging)**
- [4.1 Logs](#logs)
Expand Down Expand Up @@ -124,7 +125,9 @@ Body:
```json
{
"publicKey": "(Wireguard client public key)",
"presharedKey": "(Wireguard client preshared key)"
"presharedKey": "(Wireguard client preshared key)",
"bwLimit": (integer, megabytes, 0 for infinite),
"subExpiry": "(date in this FORMAT!! uses UTC for timing) 2021-Oct-28 12:39:05 PM"
}
```
Response:
Expand Down Expand Up @@ -210,6 +213,28 @@ Status Code `202`
}
```

### Editing subscriptions
This allows editing of subscriptions such as bandwidth, resetting bandwidth usage and changing the subscription expiry date.
URL: `POST` request to `http(s)://domain.com:PORT/manager/subscriptions/edit`
Header: `Content-Type: application/json`
Header (If authentication is enabled): `authorization:(AUTH key from .env)`
Body:
```json
{
"keyID": "(database keyID)",
"bwLimit": (integer, bandwidth limit. Set to -1 to keep current limit.),
"subExpiry": "(date, must be this format!!) 2032-Oct-21 12:49:05 PM",
"bwReset": true (a boolean, set to true to reset current bandwidth usage.)
}
```
Response:
Status Code `202`
```json
{
"response": "Disabled key successfully"
}
```

## Debugging
### Logs
If the Wireguard Manager and API application fails to start you should always look at your logs and the errors to see the problems look at ``/opt/wgManagerAPI/logs/`` folder and open the latest log using ``nano`` or any other text editor.
Expand All @@ -224,6 +249,8 @@ If the Wireguard Manager and API application fails to start you should always lo
**Q:** I have built from source code but unable to successfully route clients through the VPN
**A:** You may need the iptables rule: ``sudo iptables -t nat -A POSTROUTING -o (INTERFACE I.E eth0 or enp0s3) -j MASQUERADE``. This will be required on boot everytime. We will try and implement this into the program in the future.

**Q:** Do I need to use a wg0.conf file?
**A:** No, and please do not try, it may mess up some of the functionality we provide such as automatic deleting and re-adding keys.



12 changes: 10 additions & 2 deletions src/api/router/keyCreate.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ import (
type keyCreateJSON struct {
PublicKey string `json:"publicKey"`
PresharedKey string `json:"presharedKey"`
KeyID string `json:"keyID"`
BWLimit int64 `json:"bwLimit"`
SubExpiry string `json:"subExpiry"`
}

func keyCreate(res http.ResponseWriter, req *http.Request) {
Expand All @@ -27,7 +28,14 @@ func keyCreate(res http.ResponseWriter, req *http.Request) {
if incomingJson.PresharedKey == "" || incomingJson.PublicKey == "" {
sendResponse(res, map[string]string{"response": "Bad Request, presharedKey and publicKey must be filled"}, http.StatusBadRequest)
return
} else if incomingJson.BWLimit < 0 {
sendResponse(res, map[string]string{"response": "Bad Request, bandwidth cannot be negative"}, http.StatusBadRequest)
return
} else if incomingJson.SubExpiry == "" {
sendResponse(res, map[string]string{"response": "Bad Request, subscription expiry must be filled"}, http.StatusBadRequest)
return
}

if os.Getenv("AUTH") != "-" { //check AUTH
authHeader := req.Header.Get("Authorization")
if os.Getenv("AUTH") != authHeader {
Expand All @@ -36,7 +44,7 @@ func keyCreate(res http.ResponseWriter, req *http.Request) {
}
}

boolRes, mapRes := db.CreateKey(incomingJson.PublicKey, incomingJson.PresharedKey) //add key to db
boolRes, mapRes := db.CreateKey(incomingJson.PublicKey, incomingJson.PresharedKey, incomingJson.BWLimit, incomingJson.SubExpiry) //add key to db
if !boolRes {
sendResponse(res, mapRes, http.StatusBadRequest)
} else {
Expand Down
47 changes: 47 additions & 0 deletions src/api/router/keySetSubcription.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package router

import (
"log"
"net/http"
"os"

"gitlab.com/raspberry.tech/wireguard-manager-and-api/src/db"
)

type keySetSubJSON struct {
KeyID string `json:"keyID"`
BWLimit int64 `json:"bwLimit"`
SubExpiry string `json:"subExpiry"`
BWReset bool `json:"bwReset"`
}

func keySetSubscription(res http.ResponseWriter, req *http.Request) {
var incomingJson keySetSubJSON

err := parseResponse(req, &incomingJson) //parse JSON
if err != nil {
log.Println("Error - Parsing request", err)
sendResponse(res, map[string]string{"response": err.Error()}, http.StatusBadRequest)
return
}

if incomingJson.KeyID == "" {
sendResponse(res, map[string]string{"response": "Bad Request, keyID must be filled"}, http.StatusBadRequest)
return
}

if os.Getenv("AUTH") != "-" { //check AUTH
authHeader := req.Header.Get("Authorization")
if os.Getenv("AUTH") != authHeader {
sendResponse(res, map[string]string{"response": "Authentication key is not valid"}, http.StatusBadRequest)
return
}
}

boolRes, mapRes := db.SetSubscription(incomingJson.KeyID, incomingJson.BWLimit, incomingJson.SubExpiry, incomingJson.BWReset) //add key to db
if !boolRes {
sendResponse(res, mapRes, http.StatusBadRequest)
} else {
sendResponse(res, mapRes, http.StatusAccepted)
}
}
6 changes: 4 additions & 2 deletions src/api/router/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@ func NewRouter() *mux.Router {

manager := router.PathPrefix("/manager").Subrouter() //main subrouter

keys := manager.PathPrefix("/keys").Subrouter() //specific subrouter

keys := manager.PathPrefix("/keys").Subrouter() //specific subrouter
keys.HandleFunc("", keyCreate).Methods("POST") //post route for adding keys
keys.HandleFunc("", keyRemove).Methods("DELETE") //delete route for removing keys
keys.HandleFunc("/enable", keyEnable).Methods("POST") //post route for enabling key
keys.HandleFunc("/disable", keyDisable).Methods("POST") //post route for disabling key

subscriptions := manager.PathPrefix("/subscriptions").Subrouter() //specific subrouter
subscriptions.HandleFunc("/edit", keySetSubscription).Methods("POST") //for editing subscription
return router
}
12 changes: 9 additions & 3 deletions src/autocheck/autocheck.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,21 @@ import (
"time"

"github.com/go-co-op/gocron"
"gitlab.com/raspberry.tech/wireguard-manager-and-api/src/manager"
"gitlab.com/raspberry.tech/wireguard-manager-and-api/src/db"
)

func AutoStart() {
log.Println("Info - AutoStart running")
s := gocron.NewScheduler(time.UTC)
s.Every(5).Minutes().Do(checkPeer)
s.Every(5).Minute().Do(checkPeer)
s.Every(1).Minute().Do(checkBW)
s.StartAsync()
}

var checkPeer = func() {
log.Println("Info - Running check wg check peers")
for i := 0; i < 2; i++ {
boolWG := manager.AddRemovePeer()
boolWG := db.AddRemovePeers()
if !boolWG {
log.Println("Error - When AddRemovePeer was run")

Expand All @@ -28,3 +29,8 @@ var checkPeer = func() {
}
}
}

var checkBW = func() {
log.Println("Info - Running check bandwidth")
db.BWPeerCheck()
}
25 changes: 21 additions & 4 deletions src/db/createKey.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,25 @@ import (
"log"
"os"
"strconv"
"time"

"gitlab.com/raspberry.tech/wireguard-manager-and-api/src/logger"
"gitlab.com/raspberry.tech/wireguard-manager-and-api/src/manager"
"gorm.io/gorm"
)

func CreateKey(pubKey string, preKey string) (bool, map[string]string) {
func CreateKey(pubKey string, preKey string, bwLimit int64, subEnd string) (bool, map[string]string) {
var ipStruct IP
var wgStruct WireguardInterface
responseMap := make(map[string]string)
db := DBSystem

_, subErr := time.Parse("2006-Jan-02 03:04:05 PM", subEnd)
if !logger.ErrorHandler("Error - Parsing stored time ", subErr) {
responseMap["response"] = "Error when parsing time"
return false, responseMap
}

resultIP := db.Where("in_use = ?", "false").First(&ipStruct) //find IP not in use
if errors.Is(resultIP.Error, gorm.ErrRecordNotFound) {
responseMap["response"] = "No available IPs on the server"
Expand All @@ -29,9 +37,18 @@ func CreateKey(pubKey string, preKey string) (bool, map[string]string) {
responseMap["response"] = "Error when adding key to database"
return false, responseMap
}
ipStruct.InUse = "true" //set ip to in use
db.Save(&ipStruct) //update IP in db
keyIDStr := strconv.Itoa(keyStructCreate.KeyID) //convert keyID to string
ipStruct.InUse = "true" //set ip to in use
db.Save(&ipStruct) //update IP in db
keyIDStr := strconv.Itoa(keyStructCreate.KeyID) //convert keyID to string

subStructCreate := Subscription{KeyID: keyStructCreate.KeyID, PublicKey: pubKey, BandwidthUsed: 0, BandwidthAllotted: bwLimit, SubscriptionEnd: subEnd}
resultSub := db.Create(&subStructCreate)
if resultSub.Error != nil {
log.Println("Error - Adding subscription to db", resultKeyCreate.Error)
responseMap["response"] = "Error when adding subscription to database"
return false, responseMap
}

boolRes, strRes := manager.AddKey(ipStruct.WGInterface, ipStruct.IPv4Address, ipStruct.IPv6Address, pubKey, preKey) //add key to wg interface
if !boolRes { //if an error occurred
responseMap["response"] = strRes
Expand Down
2 changes: 1 addition & 1 deletion src/db/db.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ func DBStart() {
DBSystem = db //set global variable up

// Migrate the schema
errMigrate := db.AutoMigrate(&Key{}, &IP{}, &WireguardInterface{}) //Migrate tables to sqlite
errMigrate := db.AutoMigrate(&Key{}, &IP{}, &WireguardInterface{}, &Subscription{}) //Migrate tables to sqlite
if errMigrate != nil {
log.Fatal("Error - Migrating database", errMigrate)
} else {
Expand Down
91 changes: 91 additions & 0 deletions src/db/dbAutoChecks.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
package db

import (
"errors"
"log"
"strconv"
"time"

"gitlab.com/raspberry.tech/wireguard-manager-and-api/src/logger"
"gitlab.com/raspberry.tech/wireguard-manager-and-api/src/manager"
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
"gorm.io/gorm"
)

func AddRemovePeers() bool {
getInterfaces, err := manager.GetInterfaces()
if !logger.ErrorHandler("Info - Finding interfaces", err) {
return false
}

for interfaces := 0; interfaces < len(getInterfaces); interfaces++ { //get interfaces
for peer := 0; peer < len(getInterfaces[interfaces].Peers); peer++ {
currentPeer := getInterfaces[interfaces].Peers[peer] //get the current peer in for loop
interfaceName := getInterfaces[interfaces].Name
updateBW := manager.AddRemovePeer(currentPeer, interfaceName)
if updateBW {
updatePeerBW(currentPeer)
}
}
}
return true
}

func BWPeerCheck() bool {
getInterfaces, err := manager.GetInterfaces()
if !logger.ErrorHandler("Info - Finding interfaces", err) {
return false
}

db := DBSystem
currentTime := time.Now().UTC()
for interfaces := 0; interfaces < len(getInterfaces); interfaces++ { //get interfaces
for peer := 0; peer < len(getInterfaces[interfaces].Peers); peer++ { //get each peer in the wg interface
currentPeer := getInterfaces[interfaces].Peers[peer] //get the current peer in for loop

publicKey := currentPeer.PublicKey //get public key of client
bwCurrent := currentPeer.TransmitBytes // bandwidth used
pubKeyStr := publicKey.String()
var subStruct Subscription

resultIP := db.Where("public_key = ?", pubKeyStr).First(&subStruct) //find subscription record
if errors.Is(resultIP.Error, gorm.ErrRecordNotFound) {
log.Println("Could not find public key in database: ", pubKeyStr)
continue
}

bwStoredUsage := subStruct.BandwidthUsed
bwLimit := subStruct.BandwidthAllotted
subEnd := subStruct.SubscriptionEnd

subFormatted, subErr := time.Parse("2006-Jan-02 03:04:05 PM", subEnd)
if !logger.ErrorHandler("Error - Parsing stored time ", subErr) {
continue
}
if bwStoredUsage+(bwCurrent/1000000) > bwLimit || currentTime.After(subFormatted) {
keyID := subStruct.KeyID
updatePeerBW(currentPeer) //update bandwidth before disabling
DisableKey(strconv.Itoa(keyID)) //disable key if bandwidth limit reached or subscription end#
log.Println("Info - Disabling key, bw or sub has ended, KeyID: ", keyID)
}
}
}
return true
}

func updatePeerBW(currentPeer wgtypes.Peer) {
db := DBSystem
var subStruct Subscription

pubKey := currentPeer.PublicKey.String()
currentBytes := currentPeer.TransmitBytes

resultSub := db.Where("public_key = ?", pubKey).First(&subStruct) //find IP not in use
if errors.Is(resultSub.Error, gorm.ErrRecordNotFound) {
log.Println("Error - Subscription not found")
return //continue even on error
}
updatedBW := subStruct.BandwidthUsed + (currentBytes / 1000000)

db.Model(&Subscription{}).Where("public_key = ?", pubKey).Update("bandwidth_used", updatedBW)
}
19 changes: 14 additions & 5 deletions src/db/deleteKey.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import (
func DeleteKey(keyID string) (bool, map[string]string) {
var ipStruct IP
var keyStruct Key
var subStruct Subscription

responseMap := make(map[string]string)
db := DBSystem

Expand All @@ -22,11 +24,11 @@ func DeleteKey(keyID string) (bool, map[string]string) {
return false, responseMap
}

pubKey := keyStruct.PublicKey //set pub key
ipv4 := keyStruct.IPv4Address //set ipv4 address
resultDel := db.Where("key_id = ?", keyID).Delete(&keyStruct) //delete key from db
if resultDel.Error != nil {
log.Println("Finding key in DB", resultDel.Error)
pubKey := keyStruct.PublicKey //set pub key
ipv4 := keyStruct.IPv4Address //set ipv4 address
delKey := db.Where("key_id = ?", keyID).Delete(&keyStruct) //delete key from db
if delKey.Error != nil {
log.Println("Finding key in DB", delKey.Error)
responseMap["response"] = "Error occurred when finding the key in database"
return false, responseMap
}
Expand All @@ -43,6 +45,13 @@ func DeleteKey(keyID string) (bool, map[string]string) {
responseMap["response"] = "Error in updating IP"
return false, responseMap
}

delSub := db.Where("key_id = ?", keyID).Delete(&subStruct) //delete subcription from db
if delSub.Error != nil {
log.Println("Finding key in DB", delSub.Error)
responseMap["response"] = "Error occurred when finding the subscription in database"
return false, responseMap
}
boolRes, stringRes := manager.DeleteKey("wg0", pubKey) //delete key from wg interface
responseMap["response"] = stringRes
return boolRes, responseMap
Expand Down
Loading

0 comments on commit 50fb876

Please sign in to comment.