-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
6 changed files
with
160 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
from flask import Blueprint, Flask, request, Response, Request | ||
from ..database import db | ||
from ..models.service import Service | ||
from ..models.user import User | ||
from sqlalchemy_helpers import get_or_create | ||
from .util import not_found, success, bad_request, created, conflict, validate_request, create_event, query_fasjson | ||
from .parser.parser import msg_parser | ||
from fedora_messaging import api | ||
|
||
|
||
app = Flask(__name__) | ||
message_endpoint = Blueprint("message_endpoint", __name__) | ||
|
||
|
||
@message_endpoint.route("/message", methods=["POST"]) | ||
def create_msg(): | ||
""" | ||
Used for creating a new message by sending a post request to /message path | ||
Request Body: | ||
service_uuid: Service related to message. | ||
""" | ||
if not validate_request(request, fields=['service_uuid']): | ||
return bad_request() | ||
|
||
session = db.Session() | ||
body = request.json | ||
|
||
service = session.query(Service).filter(Service.id == body['service_uuid']).first() | ||
|
||
if service is None: | ||
return not_found() | ||
msg = msg_parser(service.type, request) | ||
api.publish(msg) | ||
|
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
|
||
from flask import Request | ||
from werkzeug.datastructures.headers import EnvironHeaders | ||
import hashlib | ||
import hmac | ||
from webhook_to_fedora_messaging_messages.github.github import GithubMessageV1 | ||
from ..util import fas_by_github | ||
|
||
|
||
|
||
def msg_parser(service_type: str, request: Request): | ||
if service_type.lower() == "github": | ||
return _github_parser(request) | ||
|
||
|
||
def _github_parser(request: Request, secret=True) -> GithubMessageV1: | ||
""" | ||
Convert Flask request objects into desired FedMsg format. | ||
Args: | ||
headers: Flask request.headers | ||
body: A dictionary contains payload | ||
secret: Specifies whether the webhook has secret key feature on or not | ||
""" | ||
|
||
headers = get_github_headers(request.headers) | ||
|
||
secret = "00b863c62c96aa67aeea966104362b1136ce883d" # will come from a data source | ||
if (secret and verify_signature(request.data, secret, headers['X-Hub-Signature-256'])) or not secret: | ||
topic = "github." + headers['X-Github-Event'] | ||
agent = fas_by_github(request.json['sender']['login']) # FASJSON | ||
return GithubMessageV1(topic=topic, body={'body': request.json, 'headers': headers, 'agent': agent}) | ||
return None | ||
|
||
|
||
def get_github_headers(headers: EnvironHeaders) -> dict: | ||
"""To change from EnvironHeaders to dict since EnvironHeaders doesn't have a copy() method. | ||
Args: | ||
headers: Flask request.headers | ||
""" | ||
|
||
return dict((key, headers[key]) for key in headers.keys()) | ||
|
||
|
||
def verify_signature(payload_body: str, secret_token: str, signature_header: str) -> bool: | ||
"""Verify that the payload was sent from GitHub by validating SHA256. | ||
Return false if not authorized. | ||
Args: | ||
payload_body: original request body to verify (request.body()) | ||
secret_token: GitHub app webhook token (WEBHOOK_SECRET) | ||
signature_header: header received from GitHub (x-hub-signature-256) | ||
""" | ||
if not signature_header: | ||
return False | ||
hash_object = hmac.new(secret_token.encode('utf-8'), msg=payload_body, digestmod=hashlib.sha256) | ||
expected_signature = "sha256=" + hash_object.hexdigest() | ||
|
||
if not hmac.compare_digest(expected_signature, signature_header): | ||
return False | ||
return True |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
from flask import Response, Request | ||
from ..config.defaults import FASJSON_URL | ||
import fasjson_client | ||
|
||
|
||
def not_found() -> Response: | ||
return Response({'message': 'Not Found'}, status=404, mimetype='application/json') | ||
|
||
|
||
def success(data: dict) ->Response: | ||
return Response(data, status=200, mimetype='application/json') | ||
|
||
|
||
def bad_request() -> Response: | ||
return Response("{'message': 'Bad Request'}", status=400, mimetype='application/json') | ||
|
||
|
||
def created(data: dict) -> Response: | ||
return Response(data, status=201, mimetype='application/json') | ||
|
||
|
||
def conflict(data: dict) -> Response: | ||
return Response(data, status=409, mimetype='application/json') | ||
|
||
|
||
def validate_request(request: Request, fields=['username']): | ||
return all(field in request for field in fields) | ||
|
||
|
||
def verify_signature(payload_body: str, secret_token: str, signature_header: str) -> bool: | ||
"""Verify that the payload was sent from GitHub by validating SHA256. | ||
Raise and return 403 if not authorized. | ||
Args: | ||
payload_body: original request body to verify (request.body()) | ||
secret_token: GitHub app webhook token (WEBHOOK_SECRET) | ||
signature_header: header received from GitHub (x-hub-signature-256) | ||
""" | ||
if not signature_header: | ||
return False | ||
hash_object = hmac.new(secret_token.encode('utf-8'), msg=payload_body, digestmod=hashlib.sha256) | ||
expected_signature = "sha256=" + hash_object.hexdigest() | ||
|
||
if not hmac.compare_digest(expected_signature, signature_header): | ||
return False | ||
return True | ||
|
||
|
||
def fas_by_github(username: str) -> str: | ||
"""Get the Fedora Account System Username of the given github username | ||
Args: | ||
username: Github Username""" | ||
|
||
fasjson = fasjson_client.Client(FASJSON_URL) | ||
response = fasjson.search(github_username=username) | ||
if response.result and len(response.result) == 1: | ||
return response.result[0]["username"] | ||
return None |