Merge pull request 'feat: Webhook use auth token' (#10) from feat/webhook-auth into main
Reviewed-on: #10
This commit is contained in:
commit
6d9626eaa2
@ -14,6 +14,12 @@ TODO
|
|||||||
- Create new user for database: `GRANT ALL PRIVILEGES ON dev_locationhub.* TO 'dbuser'@'localhost' IDENTIFIED BY '1234';`
|
- Create new user for database: `GRANT ALL PRIVILEGES ON dev_locationhub.* TO 'dbuser'@'localhost' IDENTIFIED BY '1234';`
|
||||||
- Import tables: `/usr/bin/mariadb -u dbuser -p1234 dev_locationhub < server/sql/tables.sql`
|
- Import tables: `/usr/bin/mariadb -u dbuser -p1234 dev_locationhub < server/sql/tables.sql`
|
||||||
|
|
||||||
|
### TTN Integration
|
||||||
|
Create new Webhook for application. Set base url and enable "Uplink message" to api `/api/ttn/webhook`.
|
||||||
|
Add a addidtional header:
|
||||||
|
- Type: `authorization`
|
||||||
|
- Value: `Bearer your-very-secure-token`
|
||||||
|
|
||||||
### Testing Webhook
|
### Testing Webhook
|
||||||
- To test the webhook use the python script `ttn-webhook-dummy.py` to send prerecorded TTN Uplinks.
|
- To test the webhook use the python script `ttn-webhook-dummy.py` to send prerecorded TTN Uplinks.
|
||||||
- To test the script you can use `while true; do echo -e "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\n\r\nSuccess"; nc -l -p 8080 -q 1; done`
|
- To test the script you can use `while true; do echo -e "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\n\r\nSuccess"; nc -l -p 8080 -q 1; done`
|
@ -4,6 +4,7 @@ DB_PASSWORD=""
|
|||||||
DB_HOST=""
|
DB_HOST=""
|
||||||
DB_DIALECT=""
|
DB_DIALECT=""
|
||||||
DB_PORT=""
|
DB_PORT=""
|
||||||
|
WEBHOOK_TOKEN="" #Token that is placed a the TTN Webhook auth
|
||||||
WIGLE_TOKEN="" # Go to account and generate token "Encoded for use"
|
WIGLE_TOKEN="" # Go to account and generate token "Encoded for use"
|
||||||
WIGLE_BASE_URL="https://api.wigle.net"
|
WIGLE_BASE_URL="https://api.wigle.net"
|
||||||
WIGLE_NETWORK_SEARCH="/api/v2/network/search"
|
WIGLE_NETWORK_SEARCH="/api/v2/network/search"
|
||||||
|
@ -9,11 +9,16 @@ import json
|
|||||||
import argparse
|
import argparse
|
||||||
import random
|
import random
|
||||||
|
|
||||||
def send_post_request(uri, data):
|
def send_post_request(uri, data, token):
|
||||||
|
headers = {
|
||||||
|
"Authorization": f"Bearer {token}",
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
}
|
||||||
try:
|
try:
|
||||||
requests.post(uri, json=data, timeout=1)
|
response = requests.post(uri, json=data, timeout=1, headers=headers)
|
||||||
|
print("Return code: " + str(response.status_code))
|
||||||
except requests.exceptions.RequestException as e:
|
except requests.exceptions.RequestException as e:
|
||||||
pass
|
print(e)
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
parser = argparse.ArgumentParser(
|
parser = argparse.ArgumentParser(
|
||||||
@ -24,6 +29,11 @@ def main():
|
|||||||
type=str,
|
type=str,
|
||||||
help="The URI to send POST requests to (e.g., http://127.0.0.1:8080/api)",
|
help="The URI to send POST requests to (e.g., http://127.0.0.1:8080/api)",
|
||||||
)
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"token",
|
||||||
|
type=str,
|
||||||
|
help="Bearer authorization token)",
|
||||||
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"directory",
|
"directory",
|
||||||
type=str,
|
type=str,
|
||||||
@ -46,7 +56,7 @@ def main():
|
|||||||
try:
|
try:
|
||||||
data = json.load(file)
|
data = json.load(file)
|
||||||
print(f"Sending {args.directory} to {args.uri}")
|
print(f"Sending {args.directory} to {args.uri}")
|
||||||
send_post_request(args.uri, data)
|
send_post_request(args.uri, data, args.token)
|
||||||
except json.JSONDecodeError as e:
|
except json.JSONDecodeError as e:
|
||||||
print(f"Error reading {args.directory}: {e}")
|
print(f"Error reading {args.directory}: {e}")
|
||||||
return
|
return
|
||||||
@ -67,7 +77,7 @@ def main():
|
|||||||
try:
|
try:
|
||||||
data = json.load(file)
|
data = json.load(file)
|
||||||
print(f"Sending {filename} to {args.uri}")
|
print(f"Sending {filename} to {args.uri}")
|
||||||
send_post_request(args.uri, data)
|
send_post_request(args.uri, data, args.token)
|
||||||
except json.JSONDecodeError as e:
|
except json.JSONDecodeError as e:
|
||||||
print(f"Error reading {filename}: {e}")
|
print(f"Error reading {filename}: {e}")
|
||||||
|
|
||||||
@ -78,7 +88,7 @@ def main():
|
|||||||
try:
|
try:
|
||||||
data = json.load(file)
|
data = json.load(file)
|
||||||
print(f"Sending {filename} to {args.uri}")
|
print(f"Sending {filename} to {args.uri}")
|
||||||
send_post_request(args.uri, data)
|
send_post_request(args.uri, data, args.token)
|
||||||
input("Press Enter to send the next file...")
|
input("Press Enter to send the next file...")
|
||||||
except json.JSONDecodeError as e:
|
except json.JSONDecodeError as e:
|
||||||
print(f"Error reading {filename}: {e}")
|
print(f"Error reading {filename}: {e}")
|
||||||
@ -91,11 +101,10 @@ def main():
|
|||||||
try:
|
try:
|
||||||
data = json.load(file)
|
data = json.load(file)
|
||||||
print(f"Sending {filename} to {args.uri}")
|
print(f"Sending {filename} to {args.uri}")
|
||||||
send_post_request(args.uri, data)
|
send_post_request(args.uri, data, args.token)
|
||||||
input("Press Enter to send another random file...")
|
input("Press Enter to send another random file...")
|
||||||
except json.JSONDecodeError as e:
|
except json.JSONDecodeError as e:
|
||||||
print(f"Error reading {filename}: {e}")
|
print(f"Error reading {filename}: {e}")
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
main()
|
main()
|
||||||
|
@ -7,6 +7,8 @@ import { LpTtnEndDeviceUplinksService } from "../services/lpTtnEndDeviceUplinksS
|
|||||||
import { TtnGatewayReceptionService } from "../services/ttnGatewayReceptionService";
|
import { TtnGatewayReceptionService } from "../services/ttnGatewayReceptionService";
|
||||||
import { WifiScanService } from "../services/wifiScanService";
|
import { WifiScanService } from "../services/wifiScanService";
|
||||||
import { ttnMessageValidator } from "../validation/ttn/ttnMessageValidation";
|
import { ttnMessageValidator } from "../validation/ttn/ttnMessageValidation";
|
||||||
|
import { authenticateHeader } from "../middleware/authentificationMiddleware";
|
||||||
|
import { StatusCodes } from "http-status-codes";
|
||||||
|
|
||||||
const lpTtnEndDeviceUplinksService = container.resolve(
|
const lpTtnEndDeviceUplinksService = container.resolve(
|
||||||
LpTtnEndDeviceUplinksService
|
LpTtnEndDeviceUplinksService
|
||||||
@ -22,7 +24,7 @@ const router = express.Router();
|
|||||||
|
|
||||||
router.post(
|
router.post(
|
||||||
"/webhook",
|
"/webhook",
|
||||||
validateData(ttnMessageValidator),
|
[authenticateHeader, validateData(ttnMessageValidator)],
|
||||||
async (req: Request, res: Response) => {
|
async (req: Request, res: Response) => {
|
||||||
try {
|
try {
|
||||||
const message = req.body as TtnMessage;
|
const message = req.body as TtnMessage;
|
||||||
@ -103,10 +105,10 @@ router.post(
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
createDatabaseEntries().then();
|
createDatabaseEntries().then();
|
||||||
res.status(200);
|
res.status(StatusCodes.OK).send();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error);
|
console.log(error);
|
||||||
res.status(500).json({ error: "Error creating uplink" });
|
res.status(StatusCodes.INTERNAL_SERVER_ERROR).json({ error: "Error creating uplink" });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
42
server/src/middleware/authentificationMiddleware.ts
Normal file
42
server/src/middleware/authentificationMiddleware.ts
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
import { NextFunction, Request, Response } from "express";
|
||||||
|
import { StatusCodes } from "http-status-codes";
|
||||||
|
|
||||||
|
const validateBearerToken = (authorizationHeader: string | undefined): boolean => {
|
||||||
|
if (!authorizationHeader) {
|
||||||
|
console.log("Authorization header is missing!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const token = authorizationHeader.split(' ')[1]; // Extract token after 'Bearer'
|
||||||
|
if (!token) {
|
||||||
|
console.log("Bearer token is missing!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (token !== process.env.WEBHOOK_TOKEN) {
|
||||||
|
console.log("Bearer token is incorrect!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function authenticateHeader(req: Request, res: Response, next: NextFunction) {
|
||||||
|
try {
|
||||||
|
const authorizationHeader = req.headers['authorization'];
|
||||||
|
|
||||||
|
if (!validateBearerToken(authorizationHeader as string)) {
|
||||||
|
res.status(StatusCodes.UNAUTHORIZED).json({ error: "Authentication failed" });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
console.log("Bearer token is correct!");
|
||||||
|
|
||||||
|
next();
|
||||||
|
} catch (error) {
|
||||||
|
res.status(StatusCodes.INTERNAL_SERVER_ERROR)
|
||||||
|
.json({ error: "Internal Server Error" });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user