mirror of
https://github.com/0x1d/rcond.git
synced 2025-12-14 18:25:21 +01:00
feat: add API token authentication
This commit is contained in:
5
Makefile
5
Makefile
@@ -1,3 +1,4 @@
|
||||
SHELL := bash
|
||||
ARCH ?= arm64
|
||||
ADDR ?= 0.0.0.0:8080
|
||||
|
||||
@@ -10,10 +11,10 @@ build:
|
||||
env GOOS=linux GOARCH=${ARCH} go build -o bin/rcond-${ARCH} ./cmd/rcond/main.go
|
||||
|
||||
run:
|
||||
bin/rcond-${ARCH} ${ADDR}
|
||||
source .env && bin/rcond-${ARCH} ${ADDR}
|
||||
|
||||
dev:
|
||||
go run cmd/rcond/main.go ${ADDR}
|
||||
RCOND_API_TOKEN=1234567890 go run cmd/rcond/main.go
|
||||
|
||||
upload:
|
||||
scp rcond-${ARCH} pi@rpi-40ac:/home/pi/rcond
|
||||
|
||||
19
README.md
19
README.md
@@ -1,13 +1,14 @@
|
||||
# rcond
|
||||
|
||||
A simple daemon to manage network connections through NetworkManager's D-Bus interface.
|
||||
A simple daemon to manage
|
||||
- network connections through NetworkManager's D-Bus interface
|
||||
- system hostname through the hostname1 service
|
||||
|
||||
It provides a REST API to:
|
||||
- Create and activate WiFi connections
|
||||
- Deactivate WiFi connections
|
||||
- Remove stored connection profiles
|
||||
|
||||
The daemon is designed to run on Linux systems with NetworkManager.
|
||||
- Get and set the system hostname
|
||||
|
||||
## Build and Run
|
||||
|
||||
@@ -46,6 +47,7 @@ All endpoints use JSON for request and response payloads.
|
||||
```bash
|
||||
curl -v -X POST http://localhost:8080/network/up \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "X-API-Token: 1234567890" \
|
||||
-d '{
|
||||
"interface": "wlan0",
|
||||
"ssid": "MyNetworkSSID",
|
||||
@@ -58,6 +60,7 @@ curl -v -X POST http://localhost:8080/network/up \
|
||||
```bash
|
||||
curl -v -X POST http://localhost:8080/network/down \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "X-API-Token: 1234567890" \
|
||||
-d '{
|
||||
"interface": "wlan0"
|
||||
}'
|
||||
@@ -66,13 +69,18 @@ curl -v -X POST http://localhost:8080/network/down \
|
||||
### Remove the stored connection
|
||||
|
||||
```bash
|
||||
curl -v -X POST http://localhost:8080/network/remove
|
||||
curl -v -X POST http://localhost:8080/network/remove \
|
||||
-H "X-API-Token: 1234567890" \
|
||||
-d '{
|
||||
"interface": "wlan0"
|
||||
}'
|
||||
```
|
||||
|
||||
### Get the hostname
|
||||
|
||||
```bash
|
||||
curl -v http://localhost:8080/hostname
|
||||
curl -v http://localhost:8080/hostname \
|
||||
-H "X-API-Token: 1234567890"
|
||||
```
|
||||
|
||||
### Set the hostname
|
||||
@@ -80,6 +88,7 @@ curl -v http://localhost:8080/hostname
|
||||
```bash
|
||||
curl -v -X POST http://localhost:8080/hostname \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "X-API-Token: 1234567890" \
|
||||
-d '{
|
||||
"hostname": "MyHostname"
|
||||
}'
|
||||
|
||||
@@ -8,6 +8,17 @@ servers:
|
||||
- url: http://localhost:8080
|
||||
description: Local development server
|
||||
|
||||
components:
|
||||
securitySchemes:
|
||||
ApiKeyAuth:
|
||||
type: apiKey
|
||||
in: header
|
||||
name: X-API-Token
|
||||
description: API token for authentication
|
||||
|
||||
security:
|
||||
- ApiKeyAuth: []
|
||||
|
||||
paths:
|
||||
/health:
|
||||
get:
|
||||
@@ -57,6 +68,8 @@ paths:
|
||||
description: Network interface brought up successfully
|
||||
'400':
|
||||
description: Invalid request payload
|
||||
'401':
|
||||
description: Unauthorized - invalid or missing API token
|
||||
'500':
|
||||
description: Internal server error
|
||||
|
||||
@@ -82,6 +95,8 @@ paths:
|
||||
description: Network interface brought down successfully
|
||||
'400':
|
||||
description: Invalid request payload
|
||||
'401':
|
||||
description: Unauthorized - invalid or missing API token
|
||||
'500':
|
||||
description: Internal server error
|
||||
|
||||
@@ -92,6 +107,8 @@ paths:
|
||||
responses:
|
||||
'200':
|
||||
description: Connection profile removed successfully
|
||||
'401':
|
||||
description: Unauthorized - invalid or missing API token
|
||||
'500':
|
||||
description: Internal server error
|
||||
|
||||
@@ -108,6 +125,8 @@ paths:
|
||||
type: string
|
||||
description: Current hostname
|
||||
example: "MyHostname"
|
||||
'401':
|
||||
description: Unauthorized - invalid or missing API token
|
||||
'500':
|
||||
description: Internal server error
|
||||
post:
|
||||
@@ -131,6 +150,7 @@ paths:
|
||||
description: Hostname set successfully
|
||||
'400':
|
||||
description: Invalid request payload
|
||||
'401':
|
||||
description: Unauthorized - invalid or missing API token
|
||||
'500':
|
||||
description: Internal server error
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Usage: rcond <address>
|
||||
// Usage: rcond <address> <api-token>
|
||||
|
||||
package main
|
||||
|
||||
@@ -20,12 +20,17 @@ func usage() {
|
||||
}
|
||||
|
||||
func main() {
|
||||
if len(os.Args) < 2 {
|
||||
usage()
|
||||
|
||||
addr := "0.0.0.0:8080"
|
||||
if len(os.Args) > 1 {
|
||||
addr = os.Args[1]
|
||||
}
|
||||
apiToken := os.Getenv("RCOND_API_TOKEN")
|
||||
if apiToken == "" {
|
||||
log.Fatal("RCOND_API_TOKEN environment variable not set")
|
||||
}
|
||||
|
||||
addr := os.Args[1]
|
||||
srv := http.NewServer(addr)
|
||||
srv := http.NewServer(addr, apiToken)
|
||||
srv.RegisterRoutes()
|
||||
|
||||
log.Printf("Starting server on %s", addr)
|
||||
|
||||
@@ -10,11 +10,12 @@ import (
|
||||
)
|
||||
|
||||
type Server struct {
|
||||
router *mux.Router
|
||||
srv *http.Server
|
||||
router *mux.Router
|
||||
srv *http.Server
|
||||
apiToken string
|
||||
}
|
||||
|
||||
func NewServer(addr string) *Server {
|
||||
func NewServer(addr string, apiToken string) *Server {
|
||||
router := mux.NewRouter()
|
||||
|
||||
srv := &http.Server{
|
||||
@@ -25,8 +26,9 @@ func NewServer(addr string) *Server {
|
||||
}
|
||||
|
||||
return &Server{
|
||||
router: router,
|
||||
srv: srv,
|
||||
router: router,
|
||||
srv: srv,
|
||||
apiToken: apiToken,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,13 +40,24 @@ func (s *Server) Shutdown(ctx context.Context) error {
|
||||
return s.srv.Shutdown(ctx)
|
||||
}
|
||||
|
||||
func (s *Server) verifyToken(next http.HandlerFunc) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
token := r.Header.Get("X-API-Token")
|
||||
if token == "" || token != s.apiToken {
|
||||
http.Error(w, "Unauthorized", http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
next(w, r)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) RegisterRoutes() {
|
||||
s.router.HandleFunc("/health", s.healthHandler).Methods(http.MethodGet)
|
||||
s.router.HandleFunc("/network/up", HandleNetworkUp).Methods(http.MethodPost)
|
||||
s.router.HandleFunc("/network/down", HandleNetworkDown).Methods(http.MethodPost)
|
||||
s.router.HandleFunc("/network/remove", HandleNetworkRemove).Methods(http.MethodPost)
|
||||
s.router.HandleFunc("/hostname", HandleGetHostname).Methods(http.MethodGet)
|
||||
s.router.HandleFunc("/hostname", HandleSetHostname).Methods(http.MethodPost)
|
||||
s.router.HandleFunc("/network/up", s.verifyToken(HandleNetworkUp)).Methods(http.MethodPost)
|
||||
s.router.HandleFunc("/network/down", s.verifyToken(HandleNetworkDown)).Methods(http.MethodPost)
|
||||
s.router.HandleFunc("/network/remove", s.verifyToken(HandleNetworkRemove)).Methods(http.MethodPost)
|
||||
s.router.HandleFunc("/hostname", s.verifyToken(HandleGetHostname)).Methods(http.MethodGet)
|
||||
s.router.HandleFunc("/hostname", s.verifyToken(HandleSetHostname)).Methods(http.MethodPost)
|
||||
}
|
||||
|
||||
func (s *Server) healthHandler(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
Reference in New Issue
Block a user