CatPtain commited on
Commit
0c4efc3
·
verified ·
1 Parent(s): 85bc0da

Upload 7 files

Browse files
Files changed (7) hide show
  1. .env.example +43 -0
  2. README.md +71 -17
  3. config.php +200 -132
  4. github-user-test.html +185 -0
  5. save.php +28 -3
  6. storage.php +300 -1
  7. user-manager.php +37 -109
.env.example ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # VvvebJs Environment Configuration Template
2
+ # Copy this file and configure your values in Hugging Face Space Settings
3
+
4
+ # Authentication - REQUIRED
5
+ USER_1_NAME=admin
6
+ USER_1_PASSWORD=your_secure_password
7
+
8
+ # Optional additional users (increment number for more users)
9
+ USER_2_NAME=editor
10
+ USER_2_PASSWORD=another_password
11
+
12
+ # Storage Configuration
13
+ STORAGE_TYPE=github
14
+ # Options: 'github', 'kv', 'both'
15
+
16
+ # GitHub Storage - RECOMMENDED
17
+ GITHUB_TOKEN=ghp_your_github_personal_access_token
18
+ GITHUB_OWNER=your_github_username
19
+ GITHUB_REPO=your_repository_name
20
+ GITHUB_BRANCH=main
21
+ GITHUB_PATH=pages/
22
+
23
+ # 🔄 NEW: GitHub User Management
24
+ # With these GitHub settings configured, the system will:
25
+ # 1. Store user registration data in: github.com/YOUR_OWNER/YOUR_REPO/system/users.json
26
+ # 2. Load fresh user data from GitHub on every login
27
+ # 3. Sync user data across multiple deployment instances
28
+ # 4. Support user registration, login, password changes
29
+ # 5. Maintain backward compatibility with environment variable users
30
+
31
+ # EdgeOne KV Storage - OPTIONAL
32
+ EDGEONE_KV_API_KEY=your_tencent_api_key
33
+ EDGEONE_KV_SECRET_KEY=your_tencent_secret_key
34
+ EDGEONE_KV_ZONE_ID=your_zone_id
35
+ EDGEONE_KV_NAMESPACE=vvvebjs
36
+ EDGEONE_KV_ENDPOINT=https://edgeone.tencentcloudapi.com
37
+
38
+ # GitHub User Management Benefits:
39
+ # ✅ Real-time data sync between instances
40
+ # ✅ User data never lost (stored in Git)
41
+ # ✅ Support for user registration and login
42
+ # ✅ Encrypted password storage
43
+ # ✅ Automatic user session management
README.md CHANGED
@@ -10,16 +10,29 @@ license: apache-2.0
10
 
11
  # VvvebJs - Visual Website Builder
12
 
13
- A drag & drop website builder with external storage support.
14
-
15
  ## Features
16
 
17
  - 🎨 Visual drag & drop interface
18
  - 📱 Bootstrap 5 components
19
  - 💾 GitHub & EdgeOne KV storage
20
- - 👥 Multi-user authentication
21
  - 🔄 Undo/Redo functionality
22
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
23
  ## Configuration
24
 
25
  Set these environment variables in Space Settings:
@@ -53,23 +66,64 @@ EDGEONE_KV_SECRET_KEY=your_secret_key
53
  EDGEONE_KV_ZONE_ID=your_zone_id
54
  ```
55
 
 
 
 
 
 
 
 
 
 
 
 
 
 
56
  ## Usage
57
 
58
- 1. Access your Space URL
59
- 2. Enter username/password (configured in environment variables)
60
- 3. Create and edit pages using the visual editor
61
- 4. Pages are automatically saved to external storage
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
62
 
63
- ## Deployment
64
 
65
- This Space runs on Docker and includes:
66
- - PHP 8.3 with Apache
67
- - External storage support (GitHub/EdgeOne KV)
68
- - Multi-user authentication
69
- - Automatic fallback to local storage
70
 
71
- ## Support
72
 
73
- - View configuration status at `/config.php`
74
- - Check deployment guide in `README-DEPLOY.md`
75
- - Report issues on GitHub
 
10
 
11
  # VvvebJs - Visual Website Builder
12
 
 
 
13
  ## Features
14
 
15
  - 🎨 Visual drag & drop interface
16
  - 📱 Bootstrap 5 components
17
  - 💾 GitHub & EdgeOne KV storage
18
+ - 👥 GitHub-based user management with real-time sync
19
  - 🔄 Undo/Redo functionality
20
 
21
+ ## 🔄 New: GitHub User Management System
22
+
23
+ **重要更新:** 系统现在支持基于GitHub的用户管理,确保用户数据在多个实例间实时同步。
24
+
25
+ ### 主要特性
26
+ - ✅ **实时同步:** 每次登录都从GitHub仓库加载最新用户数据
27
+ - ✅ **数据持久化:** 用户数据存储在GitHub仓库的 `system/users.json` 文件中
28
+ - ✅ **多实例同步:** 多个部署实例间自动共享用户数据
29
+ - ✅ **安全性:** 密码使用 PHP password_hash() 加密存储
30
+ - ✅ **向下兼容:** 保持与原有环境变量用户系统的兼容性
31
+
32
+ ### 用户数据存储位置
33
+ - **GitHub模式:** `https://github.com/YOUR_OWNER/YOUR_REPO/blob/main/system/users.json`
34
+ - **环境变量模式:** 通过 `USER_1_NAME`、`USER_1_PASSWORD` 等环境变量配置
35
+
36
  ## Configuration
37
 
38
  Set these environment variables in Space Settings:
 
66
  EDGEONE_KV_ZONE_ID=your_zone_id
67
  ```
68
 
69
+ ## User Management Modes
70
+
71
+ ### 1. GitHub User Management (推荐)
72
+ - 支持用户注册、登录、密码修改
73
+ - 用户数据存储在GitHub仓库中
74
+ - 多实例间自动同步
75
+ - 访问 `login.html` 进行注册/登录
76
+
77
+ ### 2. Environment Variable Mode (基础模式)
78
+ - 通过环境变量预配置用户
79
+ - 使用Basic Authentication
80
+ - 适合简单部署场景
81
+
82
  ## Usage
83
 
84
+ 1. Access the Space URL
85
+ 2. Choose login method:
86
+ - **GitHub Mode:** Visit `login.html` to register/login
87
+ - **Env Mode:** Use configured username/password
88
+ 3. Build your website visually
89
+ 4. Pages are saved to external storage automatically
90
+
91
+ ## Testing
92
+
93
+ - Visit `github-user-test.html` to test GitHub user management features
94
+ - Visit `config.php` to check system configuration and status
95
+ - Visit `github-advanced-test.php` for advanced diagnostics
96
+
97
+ ## File Structure
98
+
99
+ ```
100
+ system/
101
+ └── users.json # GitHub-managed user data
102
+
103
+ users/
104
+ ├── username1/
105
+ │ ├── page1.html
106
+ │ └── page2.html
107
+ └── username2/
108
+ ├── index.html
109
+ └── about.html
110
+ ```
111
+
112
+ ## Migration from Local User Data
113
+
114
+ If you have existing local user data in `user-data/users.json`, the system will:
115
+ 1. Automatically detect the old format
116
+ 2. Continue to work with environment variables as fallback
117
+ 3. New registrations will use GitHub storage
118
+ 4. Contact administrator for data migration assistance
119
 
120
+ ## Development
121
 
122
+ The system uses a hybrid approach:
123
+ - **Priority 1:** GitHub user management for new features
124
+ - **Fallback:** Environment variable authentication for compatibility
125
+ - **Storage:** All user files stored with user isolation
 
126
 
127
+ ## License
128
 
129
+ Apache License 2.0
 
 
config.php CHANGED
@@ -1,144 +1,212 @@
1
- <!DOCTYPE html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2
  <html lang="en">
3
  <head>
4
  <meta charset="utf-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1">
6
- <title>VvvebJs - Configuration Status</title>
7
- <link href="css/editor.css" rel="stylesheet">
8
  <style>
9
- .config-panel { max-width: 800px; margin: 50px auto; padding: 20px; }
10
- .status-item { padding: 10px; margin: 5px 0; border-radius: 5px; }
11
- .status-ok { background: #d4edda; border: 1px solid #c3e6cb; color: #155724; }
12
- .status-warning { background: #fff3cd; border: 1px solid #ffeaa7; color: #856404; }
13
- .status-error { background: #f8d7da; border: 1px solid #f5c6cb; color: #721c24; }
14
-
15
- /* Auto-redirect styles */
16
- .auto-redirect {
17
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
18
- color: white;
19
- text-align: center;
20
- padding: 20px;
21
- margin: 20px 0;
22
- border-radius: 10px;
23
- }
24
- .countdown { font-size: 2em; font-weight: bold; }
25
  </style>
26
  </head>
27
  <body>
28
- <div class="config-panel">
29
- <h1>VvvebJs Configuration Status</h1>
30
-
31
- <?php
32
- // Include the storage configuration classes
33
- require_once __DIR__ . '/storage.php';
34
-
35
- // Check configuration status
36
- $configOk = true;
37
- $errors = [];
38
-
39
- echo '<h3>Authentication</h3>';
40
- $users = StorageConfig::getUsers();
41
- if (empty($users)) {
42
- echo '<div class="status-item status-error">❌ No users configured. Please set USER_1_NAME and USER_1_PASSWORD environment variables.</div>';
43
- $configOk = false;
44
- $errors[] = 'No users configured';
45
- } else {
46
- echo '<div class="status-item status-ok">✅ ' . count($users) . ' user(s) configured</div>';
47
- foreach ($users as $username => $password) {
48
- echo '<div class="status-item status-ok">👤 User: ' . htmlspecialchars($username) . '</div>';
49
- }
50
- }
51
-
52
- echo '<h3>Storage Configuration</h3>';
53
- $storageType = StorageConfig::getStorageType();
54
- echo '<div class="status-item status-ok">📁 Storage Type: ' . htmlspecialchars($storageType) . '</div>';
55
-
56
- if (in_array($storageType, ['github', 'both'])) {
57
- echo '<h4>GitHub Storage</h4>';
58
- $github = StorageConfig::getGitHubConfig();
59
-
60
- if (empty($github['token'])) {
61
- echo '<div class="status-item status-error">❌ GitHub token not configured</div>';
62
- $configOk = false;
63
- $errors[] = 'GitHub token missing';
64
- } else {
65
- echo '<div class="status-item status-ok">✅ GitHub token configured</div>';
66
- }
67
-
68
- if (empty($github['owner']) || empty($github['repo'])) {
69
- echo '<div class="status-item status-error">❌ GitHub owner/repo not configured</div>';
70
- $configOk = false;
71
- $errors[] = 'GitHub repository not configured';
72
- } else {
73
- echo '<div class="status-item status-ok">✅ Repository: ' . htmlspecialchars($github['owner']) . '/' . htmlspecialchars($github['repo']) . '</div>';
74
- echo '<div class="status-item status-ok">🌿 Branch: ' . htmlspecialchars($github['branch']) . '</div>';
75
- echo '<div class="status-item status-ok">��� Path: ' . htmlspecialchars($github['path']) . '</div>';
76
- }
77
- }
78
-
79
- if (in_array($storageType, ['kv', 'both'])) {
80
- echo '<h4>EdgeOne KV Storage</h4>';
81
- $kv = StorageConfig::getKVConfig();
82
-
83
- if (empty($kv['api_key'])) {
84
- echo '<div class="status-item status-warning">⚠️ EdgeOne KV API key not configured</div>';
85
- } else {
86
- echo '<div class="status-item status-ok">✅ EdgeOne KV API key configured</div>';
87
- }
88
-
89
- if (empty($kv['zone_id'])) {
90
- echo '<div class="status-item status-warning">⚠️ EdgeOne Zone ID not configured</div>';
91
- } else {
92
- echo '<div class="status-item status-ok">✅ Zone ID: ' . htmlspecialchars($kv['zone_id']) . '</div>';
93
- }
94
- }
95
-
96
- // Auto-redirect if configuration is OK
97
- if ($configOk) {
98
- echo '<div class="auto-redirect">';
99
- echo '<h3>🎉 配置完成!</h3>';
100
- echo '<p>所有配置项检查通过,正在自动跳转到编辑器...</p>';
101
- echo '<div class="countdown" id="countdown">3</div>';
102
- echo '<p><a href="editor.html" style="color: white; text-decoration: underline;">立即进入编辑器</a></p>';
103
- echo '</div>';
104
- echo '<script>';
105
- echo 'let count = 3;';
106
- echo 'const countdown = document.getElementById("countdown");';
107
- echo 'const timer = setInterval(() => {';
108
- echo ' count--;';
109
- echo ' countdown.textContent = count;';
110
- echo ' if (count <= 0) {';
111
- echo ' clearInterval(timer);';
112
- echo ' window.location.href = "editor.html";';
113
- echo ' }';
114
- echo '}, 1000);';
115
- echo '</script>';
116
- } else {
117
- echo '<h3>Environment Variables Reference</h3>';
118
- echo '<div class="status-item status-warning">';
119
- echo '<strong>Required for Authentication:</strong><br>';
120
- echo 'USER_1_NAME, USER_1_PASSWORD<br>';
121
- echo 'USER_2_NAME, USER_2_PASSWORD (optional)<br><br>';
122
-
123
- echo '<strong>Required for GitHub Storage:</strong><br>';
124
- echo 'GITHUB_TOKEN, GITHUB_OWNER, GITHUB_REPO<br><br>';
125
-
126
- echo '<strong>Optional for EdgeOne KV:</strong><br>';
127
- echo 'EDGEONE_KV_API_KEY, EDGEONE_KV_ZONE_ID<br>';
128
- echo '</div>';
129
-
130
- echo '<div style="margin-top: 30px;">';
131
- echo '<a href="README-DEPLOY.md" class="btn btn-primary">📖 Deployment Guide</a>';
132
- echo '</div>';
133
- }
134
- ?>
135
-
136
- <?php if ($configOk): ?>
137
- <div style="margin-top: 30px;">
138
- <a href="editor.html" class="btn btn-primary">🚀 Launch Editor</a>
139
- <a href="README-DEPLOY.md" class="btn btn-secondary">📖 Deployment Guide</a>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
140
  </div>
141
- <?php endif; ?>
142
  </div>
143
  </body>
144
  </html>
 
1
+ <?php
2
+ require_once __DIR__ . '/storage.php';
3
+
4
+ // Try GitHub user management first
5
+ $githubUserManager = new GitHubUserManager();
6
+ $useGitHubAuth = true;
7
+
8
+ // Check authentication - prioritize GitHub user management
9
+ $authenticated = false;
10
+ if ($githubUserManager->isLoggedIn()) {
11
+ $authenticated = true;
12
+ } else {
13
+ // Fallback to environment variable authentication
14
+ if (isset($_SERVER['PHP_AUTH_USER']) && isset($_SERVER['PHP_AUTH_PW'])) {
15
+ $users = StorageConfig::getUsers();
16
+ $username = $_SERVER['PHP_AUTH_USER'];
17
+ $password = $_SERVER['PHP_AUTH_PW'];
18
+
19
+ if (isset($users[$username]) && $users[$username] === $password) {
20
+ $authenticated = true;
21
+ $useGitHubAuth = false;
22
+ }
23
+ }
24
+ }
25
+
26
+ if (!$authenticated) {
27
+ header('WWW-Authenticate: Basic realm="VvvebJs Configuration"');
28
+ header('HTTP/1.0 401 Unauthorized');
29
+ die('Authentication required');
30
+ }
31
+
32
+ ?><!DOCTYPE html>
33
  <html lang="en">
34
  <head>
35
  <meta charset="utf-8">
36
  <meta name="viewport" content="width=device-width, initial-scale=1">
37
+ <title>VvvebJs Configuration</title>
38
+ <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
39
  <style>
40
+ .status-item { padding: 5px 10px; margin: 2px 0; border-radius: 3px; }
41
+ .status-ok { background-color: #d4edda; color: #155724; }
42
+ .status-error { background-color: #f8d7da; color: #721c24; }
43
+ .status-warning { background-color: #fff3cd; color: #856404; }
44
+ .config-section { margin-bottom: 30px; }
 
 
 
 
 
 
 
 
 
 
 
45
  </style>
46
  </head>
47
  <body>
48
+ <div class="container mt-4">
49
+ <div class="row">
50
+ <div class="col-md-12">
51
+ <h1>🔧 VvvebJs 配置状态</h1>
52
+
53
+ <!-- User Management Section -->
54
+ <div class="config-section">
55
+ <h2>👥 用户管理系统</h2>
56
+ <?php if ($useGitHubAuth): ?>
57
+ <div class="status-item status-ok">✅ 使用 GitHub 用户管理 (推荐)</div>
58
+ <div class="status-item status-ok">👤 当前用户: <?= htmlspecialchars($githubUserManager->getCurrentUser()) ?></div>
59
+
60
+ <?php
61
+ // Test GitHub user data loading
62
+ try {
63
+ $userList = $githubUserManager->getUserList();
64
+ echo '<div class="status-item status-ok">📊 GitHub 用户数据: ' . count($userList) . ' 个用户</div>';
65
+ foreach ($userList as $user) {
66
+ echo '<div class="status-item status-ok"> └ ' . htmlspecialchars($user['username']) . ' (注册: ' . $user['created'] . ')</div>';
67
+ }
68
+ } catch (Exception $e) {
69
+ echo '<div class="status-item status-error">❌ GitHub 用户数据加载失败: ' . htmlspecialchars($e->getMessage()) . '</div>';
70
+ }
71
+ ?>
72
+
73
+ <div class="mt-3">
74
+ <h4>💡 GitHub 用户管理优势</h4>
75
+ <ul>
76
+ <li>✅ 用户数据存储在 GitHub 仓库中,永不丢失</li>
77
+ <li>✅ 多实例间自动同步用户数据</li>
78
+ <li>✅ 每次登录都从 GitHub 加载最新数据</li>
79
+ <li>✅ 支持用户注册、登录、密码修改等完整功能</li>
80
+ </ul>
81
+ </div>
82
+ <?php else: ?>
83
+ <div class="status-item status-warning">⚠️ 使用环境变量用户管理 (基础模式)</div>
84
+ <?php
85
+ $envUsers = StorageConfig::getUsers();
86
+ if (!empty($envUsers)) {
87
+ echo '<div class="status-item status-ok">✅ ' . count($envUsers) . ' 个环境变量用户</div>';
88
+ foreach ($envUsers as $username => $password) {
89
+ echo '<div class="status-item status-ok">👤 User: ' . htmlspecialchars($username) . '</div>';
90
+ }
91
+ } else {
92
+ echo '<div class="status-item status-error">❌ 未找到用户配置</div>';
93
+ }
94
+ ?>
95
+ <?php endif; ?>
96
+ </div>
97
+
98
+ <!-- Storage Configuration -->
99
+ <div class="config-section">
100
+ <h2>💾 存储配置</h2>
101
+ <?php
102
+ $configOk = true;
103
+ $errors = [];
104
+
105
+ $storageType = StorageConfig::getStorageType();
106
+ echo '<div class="status-item status-ok">📁 Storage Type: ' . htmlspecialchars($storageType) . '</div>';
107
+
108
+ if (in_array($storageType, ['github', 'both'])) {
109
+ echo '<h4>GitHub Storage</h4>';
110
+ $github = StorageConfig::getGitHubConfig();
111
+
112
+ if (empty($github['token'])) {
113
+ echo '<div class="status-item status-error">❌ GitHub token not configured</div>';
114
+ $configOk = false;
115
+ $errors[] = 'GitHub token missing';
116
+ } else {
117
+ echo '<div class="status-item status-ok">✅ GitHub token configured</div>';
118
+ }
119
+
120
+ if (empty($github['owner']) || empty($github['repo'])) {
121
+ echo '<div class="status-item status-error">❌ GitHub owner/repo not configured</div>';
122
+ $configOk = false;
123
+ $errors[] = 'GitHub repository not configured';
124
+ } else {
125
+ echo '<div class="status-item status-ok">✅ Repository: ' . htmlspecialchars($github['owner']) . '/' . htmlspecialchars($github['repo']) . '</div>';
126
+ echo '<div class="status-item status-ok">🌿 Branch: ' . htmlspecialchars($github['branch']) . '</div>';
127
+ echo '<div class="status-item status-ok">📂 Path: ' . htmlspecialchars($github['path']) . '</div>';
128
+ }
129
+ }
130
+
131
+ if (in_array($storageType, ['kv', 'both'])) {
132
+ echo '<h4>EdgeOne KV Storage</h4>';
133
+ $kv = StorageConfig::getKVConfig();
134
+
135
+ if (empty($kv['api_key'])) {
136
+ echo '<div class="status-item status-warning">⚠️ EdgeOne KV API key not configured</div>';
137
+ } else {
138
+ echo '<div class="status-item status-ok">✅ EdgeOne KV configured</div>';
139
+ }
140
+ }
141
+ ?>
142
+ </div>
143
+
144
+ <!-- System Status -->
145
+ <div class="config-section">
146
+ <h2>⚙️ 系统状态</h2>
147
+ <?php
148
+ if ($configOk) {
149
+ echo '<div class="status-item status-ok">✅ 系统配置正常</div>';
150
+ } else {
151
+ echo '<div class="status-item status-error">❌ 系统配置有问题</div>';
152
+ foreach ($errors as $error) {
153
+ echo '<div class="status-item status-error"> - ' . htmlspecialchars($error) . '</div>';
154
+ }
155
+ }
156
+
157
+ // Test GitHub connectivity if configured
158
+ if (!empty($github['token']) && !empty($github['owner']) && !empty($github['repo'])) {
159
+ echo '<h4>🔗 GitHub 连接测试</h4>';
160
+ try {
161
+ $branchCheck = StorageConfig::checkGitHubBranch();
162
+ if ($branchCheck['success']) {
163
+ echo '<div class="status-item status-ok">✅ GitHub 连接正常</div>';
164
+ echo '<div class="status-item status-ok">🌿 分支检查: ' . htmlspecialchars($branchCheck['message']) . '</div>';
165
+ } else {
166
+ echo '<div class="status-item status-error">❌ GitHub 连接失败: ' . htmlspecialchars($branchCheck['message']) . '</div>';
167
+ }
168
+ } catch (Exception $e) {
169
+ echo '<div class="status-item status-error">❌ GitHub 测试异常: ' . htmlspecialchars($e->getMessage()) . '</div>';
170
+ }
171
+ }
172
+ ?>
173
+ </div>
174
+
175
+ <!-- Quick Actions -->
176
+ <div class="config-section">
177
+ <h2>🚀 快速操作</h2>
178
+ <div class="row">
179
+ <div class="col-md-4">
180
+ <a href="editor.html" class="btn btn-primary btn-lg w-100">
181
+ 📝 启动编辑器
182
+ </a>
183
+ </div>
184
+ <div class="col-md-4">
185
+ <a href="login.html" class="btn btn-success btn-lg w-100">
186
+ 🔐 用户登录/注册
187
+ </a>
188
+ </div>
189
+ <div class="col-md-4">
190
+ <a href="github-advanced-test.php" class="btn btn-warning btn-lg w-100">
191
+ 🧪 高级诊断
192
+ </a>
193
+ </div>
194
+ </div>
195
+ </div>
196
+
197
+ <!-- User Data Migration Notice -->
198
+ <?php if (file_exists(__DIR__ . '/user-data/users.json')): ?>
199
+ <div class="config-section">
200
+ <div class="alert alert-info">
201
+ <h4>📋 数据迁移提示</h4>
202
+ <p>检测到本地用户数据文件 <code>user-data/users.json</code>。</p>
203
+ <p>现在系统已升级为从 GitHub 仓库加载用户数据,确保多实例间数据同步。</p>
204
+ <p>如需迁移现有用户数据,请联系管理员。</p>
205
+ </div>
206
+ </div>
207
+ <?php endif; ?>
208
+ </div>
209
  </div>
 
210
  </div>
211
  </body>
212
  </html>
github-user-test.html ADDED
@@ -0,0 +1,185 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="zh-CN">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>GitHub 用户管理系统测试</title>
7
+ <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
8
+ <style>
9
+ .test-result { margin: 10px 0; padding: 10px; border-radius: 5px; }
10
+ .test-success { background-color: #d4edda; color: #155724; border: 1px solid #c3e6cb; }
11
+ .test-error { background-color: #f8d7da; color: #721c24; border: 1px solid #f5c6cb; }
12
+ .test-info { background-color: #d1ecf1; color: #0c5460; border: 1px solid #bee5eb; }
13
+ </style>
14
+ </head>
15
+ <body>
16
+ <div class="container mt-4">
17
+ <h1>🧪 GitHub 用户管理系统测试</h1>
18
+ <p class="text-muted">此页面测试新的基于GitHub的用户数据同步功能</p>
19
+
20
+ <div id="test-results"></div>
21
+
22
+ <div class="mt-4">
23
+ <h3>🔧 测试操作</h3>
24
+ <div class="row">
25
+ <div class="col-md-6">
26
+ <div class="card">
27
+ <div class="card-header">
28
+ <h5>📊 加载GitHub用户数据</h5>
29
+ </div>
30
+ <div class="card-body">
31
+ <button class="btn btn-primary" onclick="testLoadUsers()">测试从GitHub加载用户</button>
32
+ <div id="load-users-result" class="mt-2"></div>
33
+ </div>
34
+ </div>
35
+ </div>
36
+ <div class="col-md-6">
37
+ <div class="card">
38
+ <div class="card-header">
39
+ <h5>✅ 登录状态检查</h5>
40
+ </div>
41
+ <div class="card-body">
42
+ <button class="btn btn-success" onclick="checkLoginStatus()">检查当前登录状态</button>
43
+ <div id="login-status-result" class="mt-2"></div>
44
+ </div>
45
+ </div>
46
+ </div>
47
+ </div>
48
+
49
+ <div class="row mt-3">
50
+ <div class="col-md-12">
51
+ <div class="card">
52
+ <div class="card-header">
53
+ <h5>🔐 测试用户注册功能</h5>
54
+ </div>
55
+ <div class="card-body">
56
+ <div class="row">
57
+ <div class="col-md-4">
58
+ <input type="text" class="form-control" id="test-username" placeholder="测试用户名">
59
+ </div>
60
+ <div class="col-md-4">
61
+ <input type="password" class="form-control" id="test-password" placeholder="测试密码">
62
+ </div>
63
+ <div class="col-md-4">
64
+ <button class="btn btn-warning" onclick="testRegister()">测试注册</button>
65
+ </div>
66
+ </div>
67
+ <div id="register-result" class="mt-2"></div>
68
+ </div>
69
+ </div>
70
+ </div>
71
+ </div>
72
+ </div>
73
+
74
+ <div class="mt-4">
75
+ <h3>📋 系统说明</h3>
76
+ <div class="alert alert-info">
77
+ <h5>🔄 新的GitHub用户管理特性:</h5>
78
+ <ul>
79
+ <li><strong>实时同步:</strong> 每次登录都从GitHub仓库加载最新用户数据</li>
80
+ <li><strong>数据持久化:</strong> 用户数据存储在 <code>system/users.json</code> 文件中</li>
81
+ <li><strong>多实例同步:</strong> 多个部署实例间自动共享用户数据</li>
82
+ <li><strong>安全性:</strong> 密码使用 PHP password_hash() 加密存储</li>
83
+ <li><strong>无缝迁移:</strong> 保持与原有环境变量用户系统的兼容性</li>
84
+ </ul>
85
+ </div>
86
+ </div>
87
+ </div>
88
+
89
+ <script>
90
+ function showResult(elementId, message, type = 'info') {
91
+ const element = document.getElementById(elementId);
92
+ element.innerHTML = `<div class="test-result test-${type}">${message}</div>`;
93
+ }
94
+
95
+ async function testLoadUsers() {
96
+ showResult('load-users-result', '正在测试从GitHub加载用户数据...', 'info');
97
+
98
+ try {
99
+ const response = await fetch('user-manager.php', {
100
+ method: 'POST',
101
+ headers: {
102
+ 'Content-Type': 'application/x-www-form-urlencoded',
103
+ },
104
+ body: 'action=get_user_list'
105
+ });
106
+
107
+ const result = await response.json();
108
+
109
+ if (result.success) {
110
+ let message = `✅ 成功从GitHub加载 ${result.users.length} 个用户<br>`;
111
+ result.users.forEach(user => {
112
+ message += ` - ${user.username} (${user.created})<br>`;
113
+ });
114
+ showResult('load-users-result', message, 'success');
115
+ } else {
116
+ showResult('load-users-result', `❌ 加载失败: ${result.message}`, 'error');
117
+ }
118
+ } catch (error) {
119
+ showResult('load-users-result', `❌ 网络错误: ${error.message}`, 'error');
120
+ }
121
+ }
122
+
123
+ async function checkLoginStatus() {
124
+ showResult('login-status-result', '正在检查登录状态...', 'info');
125
+
126
+ try {
127
+ const response = await fetch('user-manager.php', {
128
+ method: 'POST',
129
+ headers: {
130
+ 'Content-Type': 'application/x-www-form-urlencoded',
131
+ },
132
+ body: 'action=check_login'
133
+ });
134
+
135
+ const result = await response.json();
136
+
137
+ if (result.logged_in) {
138
+ showResult('login-status-result', `✅ 已登录用户: ${result.username}`, 'success');
139
+ } else {
140
+ showResult('login-status-result', '❌ 当前未登录', 'info');
141
+ }
142
+ } catch (error) {
143
+ showResult('login-status-result', `❌ 检查失败: ${error.message}`, 'error');
144
+ }
145
+ }
146
+
147
+ async function testRegister() {
148
+ const username = document.getElementById('test-username').value;
149
+ const password = document.getElementById('test-password').value;
150
+
151
+ if (!username || !password) {
152
+ showResult('register-result', '❌ 请填写用户名和密码', 'error');
153
+ return;
154
+ }
155
+
156
+ showResult('register-result', '正在测试注册功能...', 'info');
157
+
158
+ try {
159
+ const response = await fetch('user-manager.php', {
160
+ method: 'POST',
161
+ headers: {
162
+ 'Content-Type': 'application/x-www-form-urlencoded',
163
+ },
164
+ body: `action=register&username=${encodeURIComponent(username)}&password=${encodeURIComponent(password)}&email=test@example.com`
165
+ });
166
+
167
+ const result = await response.json();
168
+
169
+ if (result.success) {
170
+ showResult('register-result', `✅ 注册成功: ${result.message}`, 'success');
171
+ } else {
172
+ showResult('register-result', `❌ 注册失败: ${result.message}`, 'error');
173
+ }
174
+ } catch (error) {
175
+ showResult('register-result', `❌ 网络错误: ${error.message}`, 'error');
176
+ }
177
+ }
178
+
179
+ // 页面加载时自动检查登录状态
180
+ window.onload = function() {
181
+ checkLoginStatus();
182
+ };
183
+ </script>
184
+ </body>
185
+ </html>
save.php CHANGED
@@ -8,8 +8,7 @@ You may obtain a copy of the License at
8
 
9
  http://www.apache.org/licenses/LICENSE-2.0
10
 
11
- Unless required by applicable law or agreed to in writing, software
12
- distributed under the License is distributed on an "AS IS" BASIS,
13
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
  See the License for the specific language governing permissions and
15
  limitations under the License.
@@ -20,8 +19,17 @@ https://github.com/givanz/VvvebJs
20
  // Include storage classes
21
  require_once __DIR__ . '/storage.php';
22
 
23
- // Authentication check
24
  function checkAuth() {
 
 
 
 
 
 
 
 
 
25
  if (!isset($_SERVER['PHP_AUTH_USER']) || !isset($_SERVER['PHP_AUTH_PW'])) {
26
  header('WWW-Authenticate: Basic realm="VvvebJs"');
27
  header('HTTP/1.0 401 Unauthorized');
@@ -36,9 +44,26 @@ function checkAuth() {
36
  header('HTTP/1.0 401 Unauthorized');
37
  die('Invalid credentials');
38
  }
 
 
39
  }
40
 
41
  // Check authentication
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
42
  checkAuth();
43
 
44
  // Initialize storage manager
 
8
 
9
  http://www.apache.org/licenses/LICENSE-2.0
10
 
11
+ Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS,
 
12
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
  See the License for the specific language governing permissions and
14
  limitations under the License.
 
19
  // Include storage classes
20
  require_once __DIR__ . '/storage.php';
21
 
22
+ // Authentication check using GitHub-based user management
23
  function checkAuth() {
24
+ // Try GitHub user management first
25
+ $githubUserManager = new GitHubUserManager();
26
+
27
+ // Check if user is logged in via session
28
+ if ($githubUserManager->isLoggedIn()) {
29
+ return true;
30
+ }
31
+
32
+ // Fallback to Basic Auth for environment variables
33
  if (!isset($_SERVER['PHP_AUTH_USER']) || !isset($_SERVER['PHP_AUTH_PW'])) {
34
  header('WWW-Authenticate: Basic realm="VvvebJs"');
35
  header('HTTP/1.0 401 Unauthorized');
 
44
  header('HTTP/1.0 401 Unauthorized');
45
  die('Invalid credentials');
46
  }
47
+
48
+ return true;
49
  }
50
 
51
  // Check authentication
52
+ $action = $_GET['action'] ?? $_POST['action'] ?? '';
53
+
54
+ // Special handling for auth check
55
+ if ($action === 'checkAuth') {
56
+ $githubUserManager = new GitHubUserManager();
57
+ if ($githubUserManager->isLoggedIn()) {
58
+ http_response_code(200);
59
+ echo json_encode(['authenticated' => true, 'user' => $githubUserManager->getCurrentUser()]);
60
+ } else {
61
+ http_response_code(401);
62
+ echo json_encode(['authenticated' => false]);
63
+ }
64
+ exit;
65
+ }
66
+
67
  checkAuth();
68
 
69
  // Initialize storage manager
storage.php CHANGED
@@ -54,7 +54,7 @@ class StorageConfig {
54
  $safeUsername = preg_replace('/[^a-zA-Z0-9_-]/', '_', $username);
55
  return "users/{$safeUsername}/";
56
  }
57
-
58
  private static function makeGitHubRequest($url, $method = 'GET', $data = null) {
59
  $config = self::getGitHubConfig();
60
 
@@ -301,6 +301,305 @@ class StorageConfig {
301
  }
302
  }
303
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
304
  // External storage handlers
305
  class KVStorage {
306
  private $config;
 
54
  $safeUsername = preg_replace('/[^a-zA-Z0-9_-]/', '_', $username);
55
  return "users/{$safeUsername}/";
56
  }
57
+
58
  private static function makeGitHubRequest($url, $method = 'GET', $data = null) {
59
  $config = self::getGitHubConfig();
60
 
 
301
  }
302
  }
303
 
304
+ // GitHub-based User Manager
305
+ class GitHubUserManager {
306
+ private $config;
307
+ private $usersFilePath = 'system/users.json';
308
+
309
+ public function __construct() {
310
+ $this->config = StorageConfig::getGitHubConfig();
311
+ session_start();
312
+ }
313
+
314
+ /**
315
+ * Load user data from GitHub repository
316
+ */
317
+ private function loadUsersFromGitHub() {
318
+ if (empty($this->config['token']) || empty($this->config['owner']) || empty($this->config['repo'])) {
319
+ error_log("GitHub User Manager: Configuration incomplete");
320
+ return [];
321
+ }
322
+
323
+ $url = "https://api.github.com/repos/{$this->config['owner']}/{$this->config['repo']}/contents/{$this->usersFilePath}";
324
+
325
+ $result = $this->makeGitHubRequest($url, 'GET');
326
+
327
+ if ($result['http_code'] === 200) {
328
+ $fileData = json_decode($result['body'], true);
329
+ if (isset($fileData['content'])) {
330
+ $usersJson = base64_decode($fileData['content']);
331
+ $users = json_decode($usersJson, true);
332
+ if (json_last_error() === JSON_ERROR_NONE) {
333
+ error_log("GitHub User Manager: Successfully loaded " . count($users) . " users from GitHub");
334
+ return $users;
335
+ }
336
+ }
337
+ } elseif ($result['http_code'] === 404) {
338
+ // Users file doesn't exist yet, create empty structure
339
+ error_log("GitHub User Manager: Users file not found, will create on first registration");
340
+ return [];
341
+ }
342
+
343
+ error_log("GitHub User Manager: Failed to load users from GitHub. HTTP Code: " . $result['http_code']);
344
+ return [];
345
+ }
346
+
347
+ /**
348
+ * Save user data to GitHub repository
349
+ */
350
+ private function saveUsersToGitHub($users) {
351
+ if (empty($this->config['token']) || empty($this->config['owner']) || empty($this->config['repo'])) {
352
+ return false;
353
+ }
354
+
355
+ $url = "https://api.github.com/repos/{$this->config['owner']}/{$this->config['repo']}/contents/{$this->usersFilePath}";
356
+
357
+ // Get current file SHA if exists
358
+ $fileResult = $this->makeGitHubRequest($url, 'GET');
359
+ $sha = null;
360
+ $isUpdate = false;
361
+
362
+ if ($fileResult['http_code'] === 200) {
363
+ $fileData = json_decode($fileResult['body'], true);
364
+ $sha = $fileData['sha'] ?? null;
365
+ $isUpdate = true;
366
+ }
367
+
368
+ $usersJson = json_encode($users, JSON_PRETTY_PRINT);
369
+ $commitData = [
370
+ 'message' => $isUpdate ? 'Update user data' : 'Create user data file',
371
+ 'content' => base64_encode($usersJson),
372
+ 'branch' => $this->config['branch']
373
+ ];
374
+
375
+ if ($sha) {
376
+ $commitData['sha'] = $sha;
377
+ }
378
+
379
+ $result = $this->makeGitHubRequest($url, 'PUT', $commitData);
380
+
381
+ if (in_array($result['http_code'], [200, 201])) {
382
+ error_log("GitHub User Manager: Successfully saved users to GitHub");
383
+ return true;
384
+ } else {
385
+ error_log("GitHub User Manager: Failed to save users to GitHub. HTTP Code: " . $result['http_code']);
386
+ return false;
387
+ }
388
+ }
389
+
390
+ /**
391
+ * Register a new user
392
+ */
393
+ public function registerUser($username, $password, $email = '') {
394
+ // Load current users from GitHub
395
+ $users = $this->loadUsersFromGitHub();
396
+
397
+ // Check if user already exists
398
+ if (isset($users[$username])) {
399
+ return ['success' => false, 'message' => 'User already exists'];
400
+ }
401
+
402
+ // Validate username
403
+ if (!preg_match('/^[a-zA-Z0-9_-]+$/', $username) || strlen($username) < 3) {
404
+ return ['success' => false, 'message' => 'Username must be at least 3 characters and contain only letters, numbers, underscore, and dash'];
405
+ }
406
+
407
+ // Hash password
408
+ $hashedPassword = password_hash($password, PASSWORD_DEFAULT);
409
+
410
+ // Add user
411
+ $users[$username] = [
412
+ 'password' => $hashedPassword,
413
+ 'email' => $email,
414
+ 'created' => date('Y-m-d H:i:s'),
415
+ 'last_login' => null
416
+ ];
417
+
418
+ // Save to GitHub
419
+ if ($this->saveUsersToGitHub($users)) {
420
+ return ['success' => true, 'message' => 'User registered successfully'];
421
+ } else {
422
+ return ['success' => false, 'message' => 'Failed to save user data to GitHub'];
423
+ }
424
+ }
425
+
426
+ /**
427
+ * Login user
428
+ */
429
+ public function loginUser($username, $password) {
430
+ // Always load fresh user data from GitHub on login
431
+ $users = $this->loadUsersFromGitHub();
432
+
433
+ if (!isset($users[$username])) {
434
+ return ['success' => false, 'message' => 'User not found'];
435
+ }
436
+
437
+ if (password_verify($password, $users[$username]['password'])) {
438
+ $_SESSION['username'] = $username;
439
+ $_SESSION['logged_in'] = true;
440
+
441
+ // Update last login time
442
+ $users[$username]['last_login'] = date('Y-m-d H:i:s');
443
+ $this->saveUsersToGitHub($users);
444
+
445
+ return ['success' => true, 'message' => 'Login successful'];
446
+ } else {
447
+ return ['success' => false, 'message' => 'Invalid password'];
448
+ }
449
+ }
450
+
451
+ /**
452
+ * Logout user
453
+ */
454
+ public function logoutUser() {
455
+ session_destroy();
456
+ return ['success' => true, 'message' => 'Logged out successfully'];
457
+ }
458
+
459
+ /**
460
+ * Check if user is logged in
461
+ */
462
+ public function isLoggedIn() {
463
+ return isset($_SESSION['logged_in']) && $_SESSION['logged_in'] === true;
464
+ }
465
+
466
+ /**
467
+ * Get current logged in user
468
+ */
469
+ public function getCurrentUser() {
470
+ if ($this->isLoggedIn()) {
471
+ return $_SESSION['username'];
472
+ }
473
+ return null;
474
+ }
475
+
476
+ /**
477
+ * Require login
478
+ */
479
+ public function requireLogin() {
480
+ if (!$this->isLoggedIn()) {
481
+ header('Location: login.html');
482
+ exit;
483
+ }
484
+ }
485
+
486
+ /**
487
+ * Get user list (fresh from GitHub)
488
+ */
489
+ public function getUserList() {
490
+ $users = $this->loadUsersFromGitHub();
491
+ $userList = [];
492
+ foreach ($users as $username => $data) {
493
+ $userList[] = [
494
+ 'username' => $username,
495
+ 'email' => $data['email'],
496
+ 'created' => $data['created'],
497
+ 'last_login' => $data['last_login']
498
+ ];
499
+ }
500
+ return $userList;
501
+ }
502
+
503
+ /**
504
+ * Update user profile
505
+ */
506
+ public function updateUserProfile($username, $updates) {
507
+ $users = $this->loadUsersFromGitHub();
508
+
509
+ if (!isset($users[$username])) {
510
+ return ['success' => false, 'message' => 'User not found'];
511
+ }
512
+
513
+ // Update allowed fields
514
+ $allowedFields = ['email'];
515
+ foreach ($allowedFields as $field) {
516
+ if (isset($updates[$field])) {
517
+ $users[$username][$field] = $updates[$field];
518
+ }
519
+ }
520
+
521
+ // Update modified timestamp
522
+ $users[$username]['modified'] = date('Y-m-d H:i:s');
523
+
524
+ if ($this->saveUsersToGitHub($users)) {
525
+ return ['success' => true, 'message' => 'Profile updated successfully'];
526
+ } else {
527
+ return ['success' => false, 'message' => 'Failed to update profile'];
528
+ }
529
+ }
530
+
531
+ /**
532
+ * Change user password
533
+ */
534
+ public function changePassword($username, $oldPassword, $newPassword) {
535
+ $users = $this->loadUsersFromGitHub();
536
+
537
+ if (!isset($users[$username])) {
538
+ return ['success' => false, 'message' => 'User not found'];
539
+ }
540
+
541
+ // Verify old password
542
+ if (!password_verify($oldPassword, $users[$username]['password'])) {
543
+ return ['success' => false, 'message' => 'Invalid current password'];
544
+ }
545
+
546
+ // Update password
547
+ $users[$username]['password'] = password_hash($newPassword, PASSWORD_DEFAULT);
548
+ $users[$username]['modified'] = date('Y-m-d H:i:s');
549
+
550
+ if ($this->saveUsersToGitHub($users)) {
551
+ return ['success' => true, 'message' => 'Password changed successfully'];
552
+ } else {
553
+ return ['success' => false, 'message' => 'Failed to change password'];
554
+ }
555
+ }
556
+
557
+ /**
558
+ * Make GitHub API request
559
+ */
560
+ private function makeGitHubRequest($url, $method = 'GET', $data = null) {
561
+ $headers = [
562
+ 'Authorization: token ' . $this->config['token'],
563
+ 'Accept: application/vnd.github.v3+json',
564
+ 'User-Agent: VvvebJs-UserManager/1.0',
565
+ 'Content-Type: application/json'
566
+ ];
567
+
568
+ $contextOptions = [
569
+ 'http' => [
570
+ 'method' => $method,
571
+ 'header' => implode("\r\n", $headers),
572
+ 'ignore_errors' => true,
573
+ 'timeout' => 30
574
+ ]
575
+ ];
576
+
577
+ if ($data && in_array($method, ['POST', 'PUT', 'PATCH'])) {
578
+ $contextOptions['http']['content'] = json_encode($data);
579
+ }
580
+
581
+ $context = stream_context_create($contextOptions);
582
+ $response = @file_get_contents($url, false, $context);
583
+ $httpCode = 0;
584
+
585
+ if (isset($http_response_header)) {
586
+ foreach ($http_response_header as $header) {
587
+ if (preg_match('/HTTP\/\d\.\d\s+(\d+)/', $header, $matches)) {
588
+ $httpCode = (int)$matches[1];
589
+ break;
590
+ }
591
+ }
592
+ }
593
+
594
+ return [
595
+ 'body' => $response,
596
+ 'http_code' => $httpCode,
597
+ 'headers' => $http_response_header ?? [],
598
+ 'error' => $response === false ? 'Request failed' : null
599
+ ];
600
+ }
601
+ }
602
+
603
  // External storage handlers
604
  class KVStorage {
605
  private $config;
user-manager.php CHANGED
@@ -1,119 +1,13 @@
1
  <?php
2
- session_start();
3
 
4
- class UserManager {
5
- private $usersFile = 'users.json';
6
-
7
- public function __construct() {
8
- if (!file_exists($this->usersFile)) {
9
- file_put_contents($this->usersFile, json_encode([]));
10
- }
11
- }
12
-
13
- public function registerUser($username, $password, $email = '') {
14
- $users = $this->getUsers();
15
-
16
- // Check if user already exists
17
- if (isset($users[$username])) {
18
- return ['success' => false, 'message' => 'User already exists'];
19
- }
20
-
21
- // Validate username
22
- if (!preg_match('/^[a-zA-Z0-9_-]+$/', $username) || strlen($username) < 3) {
23
- return ['success' => false, 'message' => 'Username must be at least 3 characters and contain only letters, numbers, underscore, and dash'];
24
- }
25
-
26
- // Hash password
27
- $hashedPassword = password_hash($password, PASSWORD_DEFAULT);
28
-
29
- // Add user
30
- $users[$username] = [
31
- 'password' => $hashedPassword,
32
- 'email' => $email,
33
- 'created' => date('Y-m-d H:i:s'),
34
- 'last_login' => null
35
- ];
36
-
37
- if ($this->saveUsers($users)) {
38
- return ['success' => true, 'message' => 'User registered successfully'];
39
- } else {
40
- return ['success' => false, 'message' => 'Failed to save user data'];
41
- }
42
- }
43
-
44
- public function loginUser($username, $password) {
45
- $users = $this->getUsers();
46
-
47
- if (!isset($users[$username])) {
48
- return ['success' => false, 'message' => 'User not found'];
49
- }
50
-
51
- if (password_verify($password, $users[$username]['password'])) {
52
- $_SESSION['username'] = $username;
53
- $_SESSION['logged_in'] = true;
54
-
55
- // Update last login
56
- $users[$username]['last_login'] = date('Y-m-d H:i:s');
57
- $this->saveUsers($users);
58
-
59
- return ['success' => true, 'message' => 'Login successful'];
60
- } else {
61
- return ['success' => false, 'message' => 'Invalid password'];
62
- }
63
- }
64
-
65
- public function logoutUser() {
66
- session_destroy();
67
- return ['success' => true, 'message' => 'Logged out successfully'];
68
- }
69
-
70
- public function isLoggedIn() {
71
- return isset($_SESSION['logged_in']) && $_SESSION['logged_in'] === true;
72
- }
73
-
74
- public function getCurrentUser() {
75
- if ($this->isLoggedIn()) {
76
- return $_SESSION['username'];
77
- }
78
- return null;
79
- }
80
-
81
- public function requireLogin() {
82
- if (!$this->isLoggedIn()) {
83
- header('Location: login.html');
84
- exit;
85
- }
86
- }
87
-
88
- private function getUsers() {
89
- $content = file_get_contents($this->usersFile);
90
- return json_decode($content, true) ?: [];
91
- }
92
-
93
- private function saveUsers($users) {
94
- return file_put_contents($this->usersFile, json_encode($users, JSON_PRETTY_PRINT)) !== false;
95
- }
96
-
97
- public function getUserList() {
98
- $users = $this->getUsers();
99
- $userList = [];
100
- foreach ($users as $username => $data) {
101
- $userList[] = [
102
- 'username' => $username,
103
- 'email' => $data['email'],
104
- 'created' => $data['created'],
105
- 'last_login' => $data['last_login']
106
- ];
107
- }
108
- return $userList;
109
- }
110
- }
111
 
112
  // Handle AJAX requests
113
  if ($_SERVER['REQUEST_METHOD'] === 'POST') {
114
  header('Content-Type: application/json');
115
 
116
- $userManager = new UserManager();
117
  $action = $_POST['action'] ?? '';
118
 
119
  switch ($action) {
@@ -141,6 +35,40 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
141
  ]);
142
  break;
143
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
144
  default:
145
  echo json_encode(['success' => false, 'message' => 'Invalid action']);
146
  }
 
1
  <?php
2
+ require_once __DIR__ . '/storage.php';
3
 
4
+ // Use GitHub-based user management
5
+ $userManager = new GitHubUserManager();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6
 
7
  // Handle AJAX requests
8
  if ($_SERVER['REQUEST_METHOD'] === 'POST') {
9
  header('Content-Type: application/json');
10
 
 
11
  $action = $_POST['action'] ?? '';
12
 
13
  switch ($action) {
 
35
  ]);
36
  break;
37
 
38
+ case 'update_profile':
39
+ if (!$userManager->isLoggedIn()) {
40
+ echo json_encode(['success' => false, 'message' => 'Not logged in']);
41
+ break;
42
+ }
43
+ $username = $userManager->getCurrentUser();
44
+ $updates = [
45
+ 'email' => $_POST['email'] ?? ''
46
+ ];
47
+ echo json_encode($userManager->updateUserProfile($username, $updates));
48
+ break;
49
+
50
+ case 'change_password':
51
+ if (!$userManager->isLoggedIn()) {
52
+ echo json_encode(['success' => false, 'message' => 'Not logged in']);
53
+ break;
54
+ }
55
+ $username = $userManager->getCurrentUser();
56
+ $oldPassword = $_POST['old_password'] ?? '';
57
+ $newPassword = $_POST['new_password'] ?? '';
58
+ echo json_encode($userManager->changePassword($username, $oldPassword, $newPassword));
59
+ break;
60
+
61
+ case 'get_user_list':
62
+ if (!$userManager->isLoggedIn()) {
63
+ echo json_encode(['success' => false, 'message' => 'Not logged in']);
64
+ break;
65
+ }
66
+ echo json_encode([
67
+ 'success' => true,
68
+ 'users' => $userManager->getUserList()
69
+ ]);
70
+ break;
71
+
72
  default:
73
  echo json_encode(['success' => false, 'message' => 'Invalid action']);
74
  }