|
1 |
| -from flask import Flask, jsonify, request |
2 |
| -from marshmallow import ValidationError |
3 |
| -from json import dumps |
| 1 | +import json |
| 2 | + |
| 3 | +from flask import jsonify |
4 | 4 | import redis
|
5 |
| -from flask_httpauth import HTTPBasicAuth |
| 5 | +from flask import Flask, request |
| 6 | +from hmac import HMAC, compare_digest |
| 7 | +from hashlib import sha1 |
6 | 8 |
|
7 |
| -from redis_benchmarks_specification.__api__.schema import ( |
8 |
| - CommitSchema, |
9 |
| -) |
10 | 9 | from redis_benchmarks_specification.__common__.builder_schema import (
|
11 | 10 | commit_schema_to_stream,
|
12 | 11 | )
|
13 |
| -from redis_benchmarks_specification.__common__.env import ( |
14 |
| - REDIS_AUTH_SERVER_HOST, |
15 |
| - REDIS_AUTH_SERVER_PORT, |
16 |
| -) |
| 12 | +from redis_benchmarks_specification.__common__.env import PULL_REQUEST_TRIGGER_LABEL |
17 | 13 |
|
| 14 | +SIG_HEADER = "X-Hub-Signature" |
18 | 15 |
|
19 |
| -def create_app(conn, test_config=None): |
| 16 | + |
| 17 | +def create_app(conn, user, test_config=None): |
20 | 18 | app = Flask(__name__)
|
21 |
| - auth = HTTPBasicAuth() |
| 19 | + |
22 | 20 | conn = conn
|
23 | 21 |
|
24 |
| - @auth.verify_password |
25 |
| - def verify_password(username, password): |
| 22 | + # GH Token Authentication |
| 23 | + def verify_signature(req): |
26 | 24 | result = False
|
27 | 25 | try:
|
28 |
| - auth_server_conn = redis.StrictRedis( |
29 |
| - host=REDIS_AUTH_SERVER_HOST, |
30 |
| - port=REDIS_AUTH_SERVER_PORT, |
31 |
| - decode_responses=True, |
32 |
| - username=username, |
33 |
| - password=password, |
34 |
| - ) |
35 |
| - auth_server_conn.ping() |
36 |
| - result = True |
| 26 | + secret = conn.get("{}:auth_token".format(user)) |
| 27 | + sig_header = req.headers.get(SIG_HEADER) |
| 28 | + if secret is not None and sig_header is not None: |
| 29 | + if type(secret) == str: |
| 30 | + secret = secret.encode() |
| 31 | + if "sha1=" in sig_header: |
| 32 | + received_sign = sig_header.split("sha1=")[-1].strip() |
| 33 | + expected_sign = HMAC( |
| 34 | + key=secret, msg=req.data, digestmod=sha1 |
| 35 | + ).hexdigest() |
| 36 | + result = compare_digest(received_sign, expected_sign) |
37 | 37 | except redis.exceptions.ResponseError:
|
38 |
| - result = False |
| 38 | + pass |
39 | 39 | except redis.exceptions.AuthenticationError:
|
40 |
| - result = False |
| 40 | + pass |
41 | 41 | return result
|
42 | 42 |
|
43 | 43 | @app.route("/api/gh/redis/redis/commits", methods=["POST"])
|
44 |
| - @auth.login_required |
45 | 44 | def base():
|
46 |
| - # Get Request body from JSON |
47 |
| - request_data = request.json |
48 |
| - gh_org = "redis" |
49 |
| - gh_repo = "redis" |
50 |
| - schema = CommitSchema() |
51 |
| - response_data = {} |
52 |
| - err_message = "" |
53 |
| - try: |
54 |
| - # Validate request body against schema data types |
55 |
| - result = schema.load(request_data) |
56 |
| - except ValidationError as err: |
57 |
| - err_message = err.messages |
58 |
| - if result is True: |
59 |
| - # Convert request body back to JSON str |
60 |
| - data_now_json_str = dumps(result) |
| 45 | + if verify_signature(request): |
| 46 | + print(request) |
| 47 | + # Get Request body from JSON |
| 48 | + request_data = request.json |
| 49 | + if type(request_data) is str: |
| 50 | + request_data = json.loads(request_data) |
| 51 | + if type(request_data) is bytes: |
| 52 | + request_data = json.loads(request_data.decode()) |
| 53 | + |
| 54 | + gh_org = "redis" |
| 55 | + gh_repo = "redis" |
| 56 | + ref = None |
| 57 | + ref_label = None |
| 58 | + sha = None |
| 59 | + |
| 60 | + event_type = "Ignored event from webhook" |
| 61 | + use_event = False |
| 62 | + # Pull request labeled |
| 63 | + trigger_label = PULL_REQUEST_TRIGGER_LABEL |
| 64 | + if "pull_request" in request_data: |
| 65 | + action = request_data["action"] |
| 66 | + if "labeled" == action: |
| 67 | + pull_request_dict = request_data["pull_request"] |
| 68 | + head_dict = pull_request_dict["head"] |
| 69 | + repo_dict = head_dict["repo"] |
| 70 | + labels = [] |
| 71 | + if "labels" in pull_request_dict: |
| 72 | + labels = pull_request_dict["labels"] |
| 73 | + ref = head_dict["ref"] |
| 74 | + ref_label = head_dict["label"] |
| 75 | + sha = head_dict["sha"] |
| 76 | + html_url = repo_dict["html_url"].split("/") |
| 77 | + gh_repo = html_url[-1] |
| 78 | + gh_org = html_url[-2] |
| 79 | + for label in labels: |
| 80 | + label_name = label["name"] |
| 81 | + if trigger_label == label_name: |
| 82 | + use_event = True |
| 83 | + event_type = "Pull request labeled with '{}'".format( |
| 84 | + trigger_label |
| 85 | + ) |
| 86 | + |
| 87 | + # Git pushes to repo |
| 88 | + if "ref" in request_data: |
| 89 | + repo_dict = request_data["repository"] |
| 90 | + html_url = repo_dict["html_url"].split("/") |
| 91 | + gh_repo = html_url[-1] |
| 92 | + gh_org = html_url[-2] |
| 93 | + ref = request_data["ref"].split("/")[-1] |
| 94 | + ref_label = request_data["ref"] |
| 95 | + sha = request_data["after"] |
| 96 | + use_event = True |
| 97 | + event_type = "Git pushes to repo" |
| 98 | + |
| 99 | + if use_event is True: |
| 100 | + fields = {"git_hash": sha, "ref_label": ref_label, "ref": ref} |
| 101 | + app.logger.info( |
| 102 | + "Using event {} to trigger benchmark. final fields: {}".format( |
| 103 | + event_type, fields |
| 104 | + ) |
| 105 | + ) |
| 106 | + result, response_data, err_message = commit_schema_to_stream( |
| 107 | + fields, conn, gh_org, gh_repo |
| 108 | + ) |
| 109 | + app.logger.info( |
| 110 | + "Using event {} to trigger benchmark. final fields: {}".format( |
| 111 | + event_type, response_data |
| 112 | + ) |
| 113 | + ) |
61 | 114 |
|
62 |
| - result, response_data, err_message = commit_schema_to_stream( |
63 |
| - data_now_json_str, conn, gh_org, gh_repo |
64 |
| - ) |
65 |
| - if result is False: |
66 |
| - return jsonify(err_message), 400 |
| 115 | + else: |
| 116 | + app.logger.info( |
| 117 | + "{}. input json was: {}".format(event_type, request_data) |
| 118 | + ) |
| 119 | + response_data = {"message": event_type} |
67 | 120 |
|
68 |
| - # Send data back as JSON |
69 |
| - return jsonify(response_data), 200 |
| 121 | + # Send data back as JSON |
| 122 | + return jsonify(response_data), 200 |
| 123 | + else: |
| 124 | + return "Forbidden", 403 |
70 | 125 |
|
71 | 126 | return app
|
0 commit comments