martynka commited on
Commit
38cb880
·
verified ·
1 Parent(s): 6a2d501

Update Dockerfile

Browse files
Files changed (1) hide show
  1. Dockerfile +131 -15
Dockerfile CHANGED
@@ -26,6 +26,119 @@ ENV HOST=0.0.0.0 \
26
  SUDO_SECRET="$SUDO_SECRET" \
27
  FLASK_SECRET="$FLASK_SECRET" \
28
  NODE_ENV=production
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
29
  # ===== Admin Backend =====
30
  COPY <<"EOF" /app/sudo/app.py
31
  from flask import Flask, request, jsonify
@@ -36,7 +149,7 @@ import os
36
  from datetime import datetime
37
  from functools import wraps
38
 
39
- app = Flask(__name__)
40
  app.secret_key = os.getenv("FLASK_SECRET")
41
 
42
  # MongoDB connection
@@ -53,34 +166,37 @@ def sudo_required(f):
53
  return f(*args, **kwargs)
54
  return wrapper
55
 
56
- # Sudo API endpoints
 
 
 
 
 
 
 
 
 
 
 
57
  @app.route('/sudo/users', methods=['GET'])
58
- @sudo_required
59
  def list_users():
60
- users = list(db.users.find({}, {
61
- "_id": 0,
62
- "username": 1,
63
- "email": 1,
64
- "createdAt": 1,
65
- "lastLogin": 1
66
- }))
67
  return jsonify(users)
68
 
69
  @app.route('/sudo/users', methods=['POST'])
70
- @sudo_required
71
  def add_user():
72
  user_data = {
73
  "username": request.json["username"],
74
  "password": generate_password_hash(request.json["password"]),
75
- "email": request.json.get("email", ""),
76
- "createdAt": datetime.utcnow(),
77
  "role": "user"
78
  }
79
  db.users.insert_one(user_data)
80
- return jsonify({"status": "User added"}), 201
81
 
82
  @app.route('/sudo/users/<username>', methods=['DELETE'])
83
- @sudo_required
84
  def delete_user(username):
85
  result = db.users.delete_one({"username": username})
86
  if result.deleted_count == 0:
 
26
  SUDO_SECRET="$SUDO_SECRET" \
27
  FLASK_SECRET="$FLASK_SECRET" \
28
  NODE_ENV=production
29
+ #==========================
30
+ # ===== HTML Admin Panel =====
31
+ COPY <<"EOF" /app/sudo/templates/index.html
32
+ <!DOCTYPE html>
33
+ <html>
34
+ <head>
35
+ <title>LibreChat Admin</title>
36
+ <style>
37
+ body { font-family: Arial, sans-serif; margin: 0; padding: 20px; }
38
+ .container { max-width: 1000px; margin: 0 auto; }
39
+ table { width: 100%; border-collapse: collapse; margin-top: 20px; }
40
+ th, td { padding: 12px; text-align: left; border-bottom: 1px solid #ddd; }
41
+ button { padding: 6px 12px; cursor: pointer; }
42
+ .login-form { max-width: 400px; margin: 50px auto; }
43
+ </style>
44
+ </head>
45
+ <body>
46
+ <div id="login" class="login-form" style="display: block;">
47
+ <h2>Admin Login</h2>
48
+ <input type="password" id="password" placeholder="Admin Password">
49
+ <button onclick="login()">Login</button>
50
+ </div>
51
+
52
+ <div id="admin-panel" class="container" style="display: none;">
53
+ <h1>User Management</h1>
54
+ <div>
55
+ <input type="text" id="new-username" placeholder="Username">
56
+ <input type="password" id="new-password" placeholder="Password">
57
+ <button onclick="addUser()">Add User</button>
58
+ </div>
59
+ <table id="users-table">
60
+ <thead>
61
+ <tr>
62
+ <th>Username</th>
63
+ <th>Actions</th>
64
+ </tr>
65
+ </thead>
66
+ <tbody></tbody>
67
+ </table>
68
+ </div>
69
+
70
+ <script>
71
+ let authToken = '';
72
+
73
+ async function login() {
74
+ const password = document.getElementById('password').value;
75
+ const response = await fetch('/sudo/login', {
76
+ method: 'POST',
77
+ headers: { 'Content-Type': 'application/json' },
78
+ body: JSON.stringify({ password })
79
+ });
80
+
81
+ if (response.ok) {
82
+ const data = await response.json();
83
+ authToken = data.token;
84
+ document.getElementById('login').style.display = 'none';
85
+ document.getElementById('admin-panel').style.display = 'block';
86
+ loadUsers();
87
+ } else {
88
+ alert('Login failed!');
89
+ }
90
+ }
91
+
92
+ async function loadUsers() {
93
+ const response = await fetch('/sudo/users', {
94
+ headers: { 'X-Auth-Token': authToken }
95
+ });
96
+ const users = await response.json();
97
+
98
+ const tbody = document.querySelector('#users-table tbody');
99
+ tbody.innerHTML = users.map(user => `
100
+ <tr>
101
+ <td>${user.username}</td>
102
+ <td>
103
+ <button onclick="deleteUser('${user.username}')">Delete</button>
104
+ </td>
105
+ </tr>
106
+ `).join('');
107
+ }
108
+
109
+ async function addUser() {
110
+ const username = document.getElementById('new-username').value;
111
+ const password = document.getElementById('new-password').value;
112
+
113
+ const response = await fetch('/sudo/users', {
114
+ method: 'POST',
115
+ headers: {
116
+ 'Content-Type': 'application/json',
117
+ 'X-Auth-Token': authToken
118
+ },
119
+ body: JSON.stringify({ username, password })
120
+ });
121
+
122
+ if (response.ok) {
123
+ loadUsers();
124
+ document.getElementById('new-username').value = '';
125
+ document.getElementById('new-password').value = '';
126
+ }
127
+ }
128
+
129
+ async function deleteUser(username) {
130
+ if (confirm(`Delete ${username}?`)) {
131
+ await fetch(`/sudo/users/${username}`, {
132
+ method: 'DELETE',
133
+ headers: { 'X-Auth-Token': authToken }
134
+ });
135
+ loadUsers();
136
+ }
137
+ }
138
+ </script>
139
+ </body>
140
+ </html>
141
+ EOF
142
  # ===== Admin Backend =====
143
  COPY <<"EOF" /app/sudo/app.py
144
  from flask import Flask, request, jsonify
 
149
  from datetime import datetime
150
  from functools import wraps
151
 
152
+ app = Flask(__name__, template_folder='/app/sudo/templates')
153
  app.secret_key = os.getenv("FLASK_SECRET")
154
 
155
  # MongoDB connection
 
166
  return f(*args, **kwargs)
167
  return wrapper
168
 
169
+
170
+ # Routes
171
+ @app.route('/sudo')
172
+ def admin_panel():
173
+ return render_template('index.html')
174
+
175
+ @app.route('/sudo/login', methods=['POST'])
176
+ def login():
177
+ if not hmac.compare_digest(request.json.get('password') or '', ADMIN_SECRET):
178
+ return jsonify({"error": "Invalid credentials"}), 401
179
+ return jsonify({"token": ADMIN_SECRET})
180
+
181
  @app.route('/sudo/users', methods=['GET'])
182
+ @require_auth
183
  def list_users():
184
+ users = list(db.users.find({}, {"_id": 0, "username": 1}))
 
 
 
 
 
 
185
  return jsonify(users)
186
 
187
  @app.route('/sudo/users', methods=['POST'])
188
+ @require_auth
189
  def add_user():
190
  user_data = {
191
  "username": request.json["username"],
192
  "password": generate_password_hash(request.json["password"]),
 
 
193
  "role": "user"
194
  }
195
  db.users.insert_one(user_data)
196
+ return jsonify({"status": "User added"})
197
 
198
  @app.route('/sudo/users/<username>', methods=['DELETE'])
199
+ @require_auth
200
  def delete_user(username):
201
  result = db.users.delete_one({"username": username})
202
  if result.deleted_count == 0: