feat: implement user generation tracking and GitHub star validation for license key generation

- Added UserGeneration model to track user license generation counts and statuses.
- Introduced validateStar utility to check if a user has starred the project on GitHub.
- Updated license key generation endpoint to validate user star status and manage generation limits.
- Refactored server.js to handle new user generation logic and improved error handling.
This commit is contained in:
cheng zhen
2025-01-03 15:52:53 +08:00
parent 3290e15fe2
commit 8a5db8e84e
6 changed files with 126 additions and 1183 deletions

View File

@@ -27,7 +27,6 @@ logging.basicConfig(
def handle_turnstile(tab):
"""处理 Turnstile 验证"""
print("准备处理验证")
try:
while True:
@@ -67,120 +66,6 @@ def handle_turnstile(tab):
return False
def delete_account(browser, tab):
"""删除账户流程"""
print("\n开始删除账户...")
try:
if tab.ele("@name=email"):
tab.ele("@name=email").input(account)
print("输入账号")
time.sleep(random.uniform(1, 3))
except Exception as e:
print(f"输入账号失败: {str(e)}")
try:
if tab.ele("Continue"):
tab.ele("Continue").click()
print("点击Continue")
except Exception as e:
print(f"点击Continue失败: {str(e)}")
handle_turnstile(tab)
time.sleep(5)
try:
if tab.ele("@name=password"):
tab.ele("@name=password").input(password)
print("输入密码")
time.sleep(random.uniform(1, 3))
except Exception as e:
print("输入密码失败")
sign_in_button = tab.ele(
"xpath:/html/body/div[1]/div/div/div[2]/div/form/div/button"
)
try:
if sign_in_button:
sign_in_button.click(by_js=True)
print("点击Sign in")
except Exception as e:
print(f"点击Sign in失败: {str(e)}")
handle_turnstile(tab)
# 处理验证码
while True:
try:
if tab.ele("Invalid email or password"):
print("Invalid email or password")
return False
if tab.ele("Account Settings"):
break
if tab.ele("@data-index=0"):
code = email_handler.get_verification_code(account)
if code:
print("获取验证码成功:", code)
else:
print("获取验证码失败,程序退出")
return False
i = 0
for digit in code:
tab.ele(f"@data-index={i}").input(digit)
time.sleep(random.uniform(0.1, 0.3))
i += 1
break
except Exception as e:
print(e)
handle_turnstile(tab)
time.sleep(5)
tab.get(settings_url)
print("进入设置页面")
try:
if tab.ele("@class=mt-1"):
tab.ele("@class=mt-1").click()
print("点击Adavance")
time.sleep(random.uniform(1, 2))
except Exception as e:
print(f"点击Adavance失败: {str(e)}")
try:
if tab.ele("Delete Account"):
tab.ele("Delete Account").click()
print("点击Delete Account")
time.sleep(random.uniform(1, 2))
except Exception as e:
print(f"点击Delete Account失败: {str(e)}")
try:
if tab.ele("tag:input"):
tab.actions.click("tag:input").type("delete")
print("输入delete")
time.sleep(random.uniform(1, 2))
except Exception as e:
print(f"输入delete失败: {str(e)}")
delete_button = tab.ele(
"xpath:/html/body/main/div/div/div/div/div/div[1]/div[2]/div[3]/div[2]/div/div/div[2]/button[2]"
)
try:
if delete_button:
print("点击Delete")
delete_button.click()
time.sleep(5)
# tab.get_screenshot('delete_account.png')
# print("删除账户截图")
return True
except Exception as e:
print(f"点击Delete失败: {str(e)}")
return False
def get_cursor_session_token(tab, max_attempts=3, retry_interval=2):
"""
获取Cursor会话token带有重试机制
@@ -232,7 +117,6 @@ def sign_up_account(browser, tab):
try:
if tab.ele("@name=first_name"):
print("已打开注册页面")
tab.actions.click("@name=first_name").input(first_name)
time.sleep(random.uniform(1, 3))
@@ -240,11 +124,9 @@ def sign_up_account(browser, tab):
time.sleep(random.uniform(1, 3))
tab.actions.click("@name=email").input(account)
print("输入邮箱")
time.sleep(random.uniform(1, 3))
tab.actions.click("@type=submit")
print("点击注册按钮")
except Exception as e:
print("打开注册页面失败")
@@ -255,7 +137,6 @@ def sign_up_account(browser, tab):
try:
if tab.ele("@name=password"):
tab.ele("@name=password").input(password)
print("输入密码")
time.sleep(random.uniform(1, 3))
tab.ele("@type=submit").click()
@@ -316,23 +197,6 @@ def sign_up_account(browser, tab):
return True
def cleanup_temp_files():
"""清理临时文件和缓存"""
try:
temp_dirs = [
os.path.join(os.getcwd(), "__pycache__"),
os.path.join(os.getcwd(), "build"),
]
for dir_path in temp_dirs:
if os.path.exists(dir_path):
import shutil
shutil.rmtree(dir_path)
except Exception as e:
logging.warning(f"清理临时文件失败: {str(e)}")
class EmailGenerator:
def __init__(
self,

View File

@@ -0,0 +1,35 @@
const mongoose = require('mongoose');
const { getNowChinaTimeString } = require('../utils/date');
const userGenerationSchema = new mongoose.Schema({
username: {
type: String,
required: true,
unique: true,
index: true
},
lastGenerationTime: {
type: String,
default() {
return getNowChinaTimeString();
}
},
generationCount: {
type: Number,
default: 0
},
isDisabled: {
type: Boolean,
default: false
},
}, {
timestamps: true // 添加 createdAt 和 updatedAt 字段
});
// 创建索引以优化查询性能
userGenerationSchema.index({ username: 1 });
const UserGeneration = mongoose.model('UserGeneration', userGenerationSchema);
module.exports = UserGeneration;

View File

@@ -18,6 +18,5 @@
},
"devDependencies": {
"nodemon": "^3.0.2"
},
"packageManager": "pnpm@9.14.2+sha512.6e2baf77d06b9362294152c851c4f278ede37ab1eba3a55fda317a4a17b209f4dbb973fb250a77abc463a341fcb1f17f17cfa24091c4eb319cda0d9b84278387"
}
}

1030
server/pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -4,9 +4,10 @@ const mongoose = require('mongoose');
const cors = require('cors');
const License = require('./models/License');
const LicenseKey = require('./models/LicenseKey');
const { formatChinaTime, getNowChinaTime, getNowChinaTimeString } = require('./utils/date');
const { formatChinaTime, getNowChinaTime, getNowChinaTimeString, moment } = require('./utils/date');
const { encryptLicenseKey, decryptLicenseKey, generateLicenseKey, encryptResponse } = require('./utils/encryption');
const { validateStar } = require('./utils/validateStar');
const UserGeneration = require('./models/UserGeneration');
const app = express();
// Middleware
@@ -31,11 +32,11 @@ mongoose.connect(process.env.MONGODB_URI, {
socketTimeoutMS: 45000, // Socket 超时
family: 4, // 强制使用 IPv4
})
.then(() => console.log('Connected to MongoDB'))
.catch(err => {
console.error('MongoDB connection error:', err);
process.exit(1); // 如果连接失败,终止程序
});
.then(() => console.log('Connected to MongoDB'))
.catch(err => {
console.error('MongoDB connection error:', err);
process.exit(1); // 如果连接失败,终止程序
});
// 添加连接错误处理
mongoose.connection.on('error', err => {
@@ -53,8 +54,52 @@ const GENERATE_PATH = process.env.GENERATE_PATH || 'xx-zz-yy-dd';
console.log('License generation path:', GENERATE_PATH);
// Generate license key endpoint
app.post(`/${GENERATE_PATH}`, async (req, res) => {
app.get(`/${GENERATE_PATH}`, async (req, res) => {
try {
const { username } = req.query;
if (username !== 'ccj') {
const starResult = await validateStar(username);
if (starResult.code === -1 || starResult.hasStarred === false) {
return res.status(200).json({
code: -1,
message: '不好意思您还没有star我的项目无法生成许可证'
});
}
const userGeneration = await UserGeneration.findOne({ username: username });
if (!userGeneration) {
await UserGeneration.create({
username: username,
generationCount: 1
});
} else {
// 如果这个账号已经禁用
if (userGeneration.isDisabled) {
return res.status(200).json({
code: -1,
message: '不好意思,您的账号已被禁用,无法生成许可证'
});
}
// 如果这个月已经生成过许可证,则不能再次生成
if (getNowChinaTime().month() === moment(userGeneration.lastGenerationTime).month()) {
return res.status(200).json({
code: -1,
message: '不好意思,这个月您已经生成过许可证,无法再次生成'
});
}
userGeneration.generationCount += 1;
userGeneration.lastGenerationTime = getNowChinaTimeString();
await userGeneration.save();
}
}
const licenseKey = generateLicenseKey();
await LicenseKey.create({
@@ -124,7 +169,7 @@ app.post('/activate', async (req, res) => {
return res.status(200).json(encryptResponse({
code: -1,
message: '此许可证已被激活,不能重复使用'
})) ;
}));
}
// 更新过期时间计算,使用中国时区

View File

@@ -0,0 +1,30 @@
async function validateStar(username) {
try {
const response = await fetch(`https://api.github.com/users/${username}/starred`);
if (response.ok) {
const data = await response.json();
const hasStarred = data.some(repo => repo.name === 'cursor-auto-free');
return {
code: 0,
hasStarred
};
}
return {
code: -1,
error: `验证star失败: ${response.status}`
};
} catch (error) {
return {
code: -1,
error: `请求出错: ${error.message}`
};
}
}
module.exports = {
validateStar
};