浏览代码

Add admin functionality

master
Chris Smith 5 年前
父节点
当前提交
e108295117
共有 4 个文件被更改,包括 78 次插入2 次删除
  1. 1
    0
      README.md
  2. 59
    2
      main.py
  3. 18
    0
      templates/admin.html
  4. 0
    0
      templates/index.html

+ 1
- 0
README.md 查看文件

@@ -17,6 +17,7 @@ Environment variable | Description
17 17
 -------------------- | --------------------------------------------------------
18 18
  `LAS_BASE_URL`      | Base web-facing URL at which LaS is accessible, used to generate hook URLs
19 19
  `LAS_SECRET`        | Random string used to generate secure hook URLs
20
+ `LAS_ADMIN_PASSWORD`| Password to require for web-based admin functionality
20 21
 
21 22
 ### URL format
22 23
 

+ 59
- 2
main.py 查看文件

@@ -1,4 +1,8 @@
1
-from flask import Flask, abort, request
1
+import os
2
+
3
+from collections import deque
4
+from flask import Flask, abort, request, Response, render_template
5
+from functools import wraps
2 6
 
3 7
 from lineandsinker.common import get_hook_key
4 8
 from lineandsinker.services import services
@@ -10,11 +14,13 @@ def refresh_services():
10 14
 
11 15
 
12 16
 refresh_services()
17
+history = deque(maxlen=100)
13 18
 app = Flask(__name__)
14 19
 
15 20
 
16 21
 def handle_events(events):
17 22
     for event in events:
23
+        history.append(event)
18 24
         if event["type"] == "git.push":
19 25
             services["jenkins"].build_job_by_scm_url(event["repo"]["urls"])
20 26
             if event["repo"]["public"]:
@@ -35,7 +41,7 @@ def handle_events(events):
35 41
 
36 42
 @app.route("/")
37 43
 def handle_index():
38
-    return app.send_static_file("index.html")
44
+    return render_template("index.html")
39 45
 
40 46
 
41 47
 @app.route("/hooks/<service>/<path:identifier>/<hash>", methods=["GET", "POST"])
@@ -44,10 +50,30 @@ def handle_hook(service, identifier, hash):
44 50
 
45 51
     expected_hash = get_hook_key(service, identifier)
46 52
     if hash != expected_hash:
53
+        handle_events(
54
+            [
55
+                {
56
+                    "type": "lineandsinker.badhash",
57
+                    "service": service,
58
+                    "hash": hash,
59
+                    "body": request.get_data(as_text=True),
60
+                }
61
+            ]
62
+        )
47 63
         app.logger.info(f"Hash not valid. Expected: {expected_hash}, got {hash}")
48 64
         abort(403)
49 65
 
50 66
     if service not in services:
67
+        handle_events(
68
+            [
69
+                {
70
+                    "type": "lineandsinker.badservice",
71
+                    "service": service,
72
+                    "known_services": list(services.keys()),
73
+                    "body": request.get_data(as_text=True),
74
+                }
75
+            ]
76
+        )
51 77
         app.logger.info(f"Unknown service {service}, known: {services.keys()}")
52 78
         abort(404)
53 79
 
@@ -56,5 +82,36 @@ def handle_hook(service, identifier, hash):
56 82
     return "", 200
57 83
 
58 84
 
85
+if "LAS_ADMIN_PASSWORD" in os.environ:
86
+
87
+    def requires_auth(f):
88
+        @wraps(f)
89
+        def decorated(*args, **kwargs):
90
+            auth = request.authorization
91
+            if (
92
+                not auth
93
+                or auth.username != "admin"
94
+                or auth.password != os.environ["LAS_ADMIN_PASSWORD"]
95
+            ):
96
+                return Response(
97
+                    "Restricted resource",
98
+                    401,
99
+                    {"WWW-Authenticate": 'Basic realm="Login Required"'},
100
+                )
101
+            return f(*args, **kwargs)
102
+
103
+        return decorated
104
+
105
+    @app.route("/admin")
106
+    @requires_auth
107
+    def handle_admin():
108
+        return render_template("admin.html", events=history)
109
+
110
+    @app.route("/admin/hash", methods=["POST"])
111
+    @requires_auth
112
+    def handle_admin_hash():
113
+        return get_hook_key(request.form["service"], request.form["identifier"]), 200
114
+
115
+
59 116
 if __name__ == "__main__":
60 117
     app.run("0.0.0.0")

+ 18
- 0
templates/admin.html 查看文件

@@ -0,0 +1,18 @@
1
+<!DOCTYPE html>
2
+<html>
3
+<head>
4
+    <title>Line and Sinker Administration</title>
5
+</head>
6
+<body>
7
+    <h1>Determine hash</h1>
8
+    <form action="/admin/hash" method="post">
9
+        <label>Service: <input type="text" name="service"></label>
10
+        <label>Identifier: <input type="text" name="identifier"></label>
11
+        <input type="submit" value="Calculate">
12
+    </form>
13
+    <h1>Recent events</h1>
14
+    {% for item in events|reverse %}
15
+        <pre>{{ item|tojson(indent=4) }}</pre>
16
+    {% endfor %}
17
+</body>
18
+</html>

static/index.html → templates/index.html 查看文件


正在加载...
取消
保存