server.js 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. require('dotenv').config();
  2. const express = require('express');
  3. const mongoose = require('mongoose');
  4. const cors = require('cors');
  5. const License = require('./models/License');
  6. const LicenseKey = require('./models/LicenseKey');
  7. const { formatChinaTime, getNowChinaTime, getNowChinaTimeString } = require('./utils/date');
  8. const { encryptLicenseKey, decryptLicenseKey, generateLicenseKey, encryptResponse } = require('./utils/encryption');
  9. const app = express();
  10. // Middleware
  11. app.use(cors());
  12. app.use(express.json());
  13. // 添加访问日志中间件
  14. app.use((req, res, next) => {
  15. const start = Date.now();
  16. res.on('finish', () => {
  17. const duration = Date.now() - start;
  18. console.log(`[${getNowChinaTimeString()}] ${req.method} ${req.originalUrl} - ${res.statusCode} - ${duration}ms`);
  19. });
  20. next();
  21. });
  22. // Connect to MongoDB
  23. mongoose.connect(process.env.MONGODB_URI, {
  24. useNewUrlParser: true,
  25. useUnifiedTopology: true,
  26. serverSelectionTimeoutMS: 5000, // 超时时间
  27. socketTimeoutMS: 45000, // Socket 超时
  28. family: 4, // 强制使用 IPv4
  29. })
  30. .then(() => console.log('Connected to MongoDB'))
  31. .catch(err => {
  32. console.error('MongoDB connection error:', err);
  33. process.exit(1); // 如果连接失败,终止程序
  34. });
  35. // 添加连接错误处理
  36. mongoose.connection.on('error', err => {
  37. console.error('MongoDB connection error:', err);
  38. });
  39. mongoose.connection.on('disconnected', () => {
  40. console.log('MongoDB disconnected');
  41. });
  42. // 定义一个复杂的路径,可以放在环境变量中
  43. const GENERATE_PATH = process.env.GENERATE_PATH || 'xx-zz-yy-dd';
  44. // 在应用启动时输出生成路径(仅在控制台显示一次)
  45. console.log('License generation path:', GENERATE_PATH);
  46. // Generate license key endpoint
  47. app.post(`/${GENERATE_PATH}`, async (req, res) => {
  48. try {
  49. const licenseKey = generateLicenseKey();
  50. await LicenseKey.create({
  51. licenseKey: licenseKey,
  52. isUsed: false
  53. });
  54. // 加密响应数据
  55. const responseData = {
  56. code: 0,
  57. data: licenseKey
  58. };
  59. return res.json(responseData);
  60. } catch (error) {
  61. console.error('生成许可证错误:', error);
  62. return res.status(500).json(encryptResponse({
  63. code: -1,
  64. message: '服务器错误'
  65. }));
  66. }
  67. });
  68. // Activation endpoint
  69. app.post('/activate', async (req, res) => {
  70. try {
  71. const { license_key, machine_code, activation_date } = req.body;
  72. // Validate input
  73. if (!license_key || !machine_code) {
  74. return res.status(200).json(encryptResponse({
  75. code: -1,
  76. message: '许可证密钥和机器码是必需的'
  77. }));
  78. }
  79. // Validate license key format
  80. try {
  81. decryptLicenseKey(license_key);
  82. } catch (error) {
  83. return res.status(200).json(encryptResponse({
  84. code: -1,
  85. message: '无效的许可证密钥'
  86. }));
  87. }
  88. // 检查许可证是否存在于生成记录中
  89. const licenseKeyRecord = await LicenseKey.findOne({ licenseKey: license_key });
  90. if (!licenseKeyRecord) {
  91. return res.status(200).json(encryptResponse({
  92. code: -1,
  93. message: '无效的许可证密钥'
  94. }));
  95. }
  96. // 检查许可证是否已被使用
  97. if (licenseKeyRecord.isUsed) {
  98. return res.status(200).json(encryptResponse({
  99. code: -1,
  100. message: '此许可证密钥已被使用,不能重复激活'
  101. }));
  102. }
  103. // 检查许可证激活状态
  104. const existingLicense = await License.findOne({ licenseKey: license_key });
  105. if (existingLicense) {
  106. return res.status(200).json(encryptResponse({
  107. code: -1,
  108. message: '此许可证已被激活,不能重复使用'
  109. })) ;
  110. }
  111. // 更新过期时间计算,使用中国时区
  112. const expiryDate = formatChinaTime(getNowChinaTime().add(1, 'month'), 'YYYY-MM-DD');
  113. await License.create([{
  114. licenseKey: license_key,
  115. machineCode: machine_code,
  116. activationDate: activation_date ? activation_date : getNowChinaTimeString(),
  117. expiryDate: expiryDate,
  118. isActive: true,
  119. maxUsageCount: process.env.MAX_USAGE_COUNT || 10,
  120. currentUsageCount: 1
  121. }]);
  122. // 更新许可证密钥状态为已使用
  123. licenseKeyRecord.isUsed = true;
  124. await licenseKeyRecord.save();
  125. const responseData = {
  126. code: 0,
  127. message: '激活成功',
  128. data: {
  129. expiry_date: expiryDate
  130. }
  131. };
  132. return res.json(encryptResponse(responseData));
  133. } catch (error) {
  134. console.error('激活错误:', error);
  135. return res.status(500).json(encryptResponse({
  136. code: -1,
  137. message: '服务器错误'
  138. }));
  139. }
  140. });
  141. // Verification endpoint
  142. app.post('/verify', async (req, res) => {
  143. try {
  144. const { license_key, machine_code } = req.body;
  145. // Validate input
  146. if (!license_key || !machine_code) {
  147. return res.status(200).json(encryptResponse({
  148. code: -1,
  149. message: '许可证密钥和机器码是必需的'
  150. }));
  151. }
  152. // Validate license key format
  153. try {
  154. decryptLicenseKey(license_key);
  155. } catch (error) {
  156. return res.status(200).json(encryptResponse({
  157. code: -1,
  158. message: '无效的许可证密钥'
  159. }));
  160. }
  161. // Find license
  162. const license = await License.findOne({ licenseKey: license_key });
  163. if (!license) {
  164. return res.status(200).json(encryptResponse({
  165. code: -1,
  166. message: '许可证不存在'
  167. }));
  168. }
  169. // Check machine code
  170. if (license.machineCode !== machine_code) {
  171. return res.status(200).json(encryptResponse({
  172. code: -1,
  173. message: '硬件信息不匹配'
  174. }));
  175. }
  176. // Check if license is active
  177. if (!license.isActive) {
  178. return res.status(200).json(encryptResponse({
  179. code: -1,
  180. message: '许可证已被禁用'
  181. }));
  182. }
  183. // 使用中国时区检查过期时间
  184. if (getNowChinaTime().isAfter(license.expiryDate)) {
  185. return res.status(200).json(encryptResponse({
  186. code: -1,
  187. message: '许可证已过期'
  188. }));
  189. }
  190. // 检查使用次数
  191. if (license.currentUsageCount >= license.maxUsageCount) {
  192. return res.status(200).json(encryptResponse({
  193. code: -1,
  194. message: '许可证使用次数已达到上限'
  195. }));
  196. }
  197. // 更新使用次数
  198. license.currentUsageCount += 1;
  199. await license.save();
  200. const responseData = {
  201. code: 0,
  202. data: {
  203. message: '许可证有效',
  204. expiry_date: formatChinaTime(license.expiryDate, 'YYYY-MM-DD'),
  205. usage_count: {
  206. current: license.currentUsageCount,
  207. max: license.maxUsageCount
  208. }
  209. }
  210. };
  211. return res.json(encryptResponse(responseData));
  212. } catch (error) {
  213. console.error('验证错误:', error);
  214. return res.status(500).json(encryptResponse({
  215. code: -1,
  216. message: '服务器错误'
  217. }));
  218. }
  219. });
  220. const PORT = process.env.PORT || 3000;
  221. app.listen(PORT, () => {
  222. console.log(`Server is running on port ${PORT}`);
  223. });