commit 4da5047bf28d131ed35136f9e4b4f67f6104840f Author: qubiaobiao <3294694717@qq.com> Date: Fri Mar 27 17:57:07 2026 +0800 短报文教学 diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 0000000..4ebc8ae --- /dev/null +++ b/.eslintignore @@ -0,0 +1 @@ +coverage diff --git a/.eslintrc b/.eslintrc new file mode 100644 index 0000000..f304bdd --- /dev/null +++ b/.eslintrc @@ -0,0 +1,4 @@ +{ + "extends": "eslint-config-egg", + "root": true +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..652759b --- /dev/null +++ b/.gitignore @@ -0,0 +1,15 @@ +logs/ +npm-debug.log +yarn-error.log +node_modules/ +*-lock.json +*-lock.yaml +yarn.lock +coverage/ +.idea/ +run/ +.DS_Store +*.sw* +*.un~ +typings/ +.nyc_output/ diff --git a/.sequelizerc b/.sequelizerc new file mode 100644 index 0000000..01d9847 --- /dev/null +++ b/.sequelizerc @@ -0,0 +1,10 @@ +'use strict'; + +const path = require('path'); + +module.exports = { + "config": path.join(__dirname, 'database/config.json'), + 'migrations-path': path.join(__dirname, 'database/migrations'), + 'seeders-path': path.join(__dirname, 'database/seeders'), + 'models-path': path.join(__dirname, 'app/model'), +}; diff --git a/README.md b/README.md new file mode 100644 index 0000000..6a02535 --- /dev/null +++ b/README.md @@ -0,0 +1,31 @@ +# open-map-assistant + + + +## QuickStart + + + +see [egg docs][egg] for more detail. + +### Development + +```bash +npm i +npm run dev +open http://localhost:7001/ +``` + +### Deploy + +```bash +npm start +npm stop +``` + +### npm scripts + +- Use `npm run lint` to check code style. +- Use `npm test` to run unit test. + +[egg]: https://eggjs.org diff --git a/app/controller/home.js b/app/controller/home.js new file mode 100644 index 0000000..ceb1c99 --- /dev/null +++ b/app/controller/home.js @@ -0,0 +1,96 @@ +const BaseController = require('../core/base_controller.js'); + +const fileName = "home"; + +class HomeController extends BaseController { + // token状态查询接口 + async tokenStatus() { + const { ctx } = this; + try { + const uid = this.decryptRequest(ctx.request.body.uid).split('?')[0]; + let rdmcode = await this.checkUid(ctx, uid); + if (!rdmcode) { + this.setResponse(ctx, 401, 'token 过期或错误', "none"); + return; + } + const result = await ctx.service.home.tokenStatus(uid); + if (result == "error") { + this.setResponse(ctx, 500, '服务器错误', "none"); + return; + } + if (result) { + this.setResponse(ctx, 200, 'token 状态查询成功', "deconstruction", result); + } else { + this.setResponse(ctx, 404, 'token 状态查询失败', "none"); + } + } catch (error) { + const blockName = fileName + "--" + "tokenStatus"; + ctx.app.middleware.log('../../controllerLog', blockName + ">>>>" + error); + this.setResponse(ctx, 500, '服务器错误', "none"); + } + } + + // 用户获取短期token的接口 + async getUserToken() { + const { ctx } = this; + try { + const uid = this.decryptRequest(ctx.request.body.uid).split('?')[0]; + if (uid == "") { + this.setResponse(ctx, 404, '获取临时 token 失败', "none"); + return; + } + let rdmcode = await this.checkUid(ctx); + if (!rdmcode) { + this.setResponse(ctx, 401, 'token 过期或错误', "none"); + return; + } + const result = await ctx.service.home.getUserToken(uid); + if (result == "error") { + this.setResponse(ctx, 500, '服务器错误', "none"); + return; + } + if (result) { + this.setResponse(ctx, 200, '获取临时 token 成功', "none"); + } else { + this.setResponse(ctx, 404, '获取临时 token 失败', "none"); + } + } catch (error) { + const blockName = fileName + "--" + "getUserToken"; + ctx.app.middleware.log('../../controllerLog', blockName + ">>>>" + error); + this.setResponse(ctx, 500, '服务器错误', "none"); + } + } + + // 用户延续短期token有效时间的接口 + async lifeHold() { + const { ctx } = this; + try { + const uid = this.decryptRequest(ctx.request.body.uid).split('?')[0]; + if (uid == "") { + this.setResponse(ctx, 404, '延续临时 token 有效时间失败', "none"); + return; + } + let rdmcode = await this.checkUid(ctx); + if (!rdmcode) { + this.setResponse(ctx, 401, 'token 过期或错误', "none"); + return; + } + const result = await ctx.service.home.lifeHold(uid); + if (result == "error") { + this.setResponse(ctx, 500, '服务器错误', "none"); + return; + } + if (result) { + this.setResponse(ctx, 200, '延续临时 token 有效时间成功', "none"); + } else { + this.setResponse(ctx, 404, '延续临时 token 有效时间失败', "none"); + } + } catch (error) { + const blockName = fileName + "--" + "lifeHold"; + ctx.app.middleware.log('../../controllerLog', blockName + ">>>>" + error); + this.setResponse(ctx, 500, '服务器错误', "none"); + } + } +} + +module.exports = HomeController; diff --git a/app/controller/teaching.js b/app/controller/teaching.js new file mode 100644 index 0000000..c2f966b --- /dev/null +++ b/app/controller/teaching.js @@ -0,0 +1,73 @@ +const BaseController = require('../core/base_controller.js'); + +const fileName = "teaching"; + +class TeachingController extends BaseController { + // 获取最近发送的一条信息 + async getMsg() { + const { ctx } = this; + try { + const redis = ctx.app.redis; + const token = ctx.request.query.token; + this.banManager(redis, token); + const result = await ctx.service.teaching.getMsg(redis, token); + if (result == "error") { + this.setResponse(ctx, 500, '服务器错误', "none"); + } else if (result.code == 401) { + this.setResponse(ctx, 't401', 'token 过期或错误', "none"); + } else if (result.code == 403) { + this.setResponse(ctx, 403, '此 token 已进入黑名单,请等待解封后再使用', "none"); + } else if (result.code == 200) { + delete result.code; + const data = { + userData: result.userData, + responseTime: new Date() + }; + this.setResponse(ctx, 200, '最近消息查询成功', "deconstruction", data); + } else { + this.setResponse(ctx, 404, '最近消息查询失败', "none"); + } + } catch (error) { + const blockName = fileName + "--" + "getMsg"; + ctx.app.middleware.log('../../controllerLog', blockName + ">>>>" + error); + this.setResponse(ctx, 500, '服务器错误', "none"); + } + } + + // 获取若干条历史消息 + async getHistory() { + const { ctx } = this; + try { + const redis = ctx.app.redis; + const { token, limit, offset } = ctx.request.query; + this.banManager(redis, token); + const result = await ctx.service.teaching.getHistory(redis, token, limit, offset); + if (result == "error") { + this.setResponse(ctx, 500, '服务器错误', "none"); + } else if (result.code == 401) { + this.setResponse(ctx, 't401', 'token 过期或错误', "none"); + } else if (result.code == 403) { + this.setResponse(ctx, 403, '此 token 已进入黑名单,请等待解封后再使用', "none"); + } else if (result.code == 200) { + delete result.code; + let historyMsg = []; + result.userData.rows.forEach(element => { + historyMsg.push(element.dataValues); + }); + const data = { + userData: historyMsg, + total: result.userData.count + }; + this.setResponse(ctx, 200, '历史消息查询成功', "deconstruction", data); + } else { + this.setResponse(ctx, 404, '历史消息查询失败', "none"); + } + } catch (error) { + const blockName = fileName + "--" + "getHistory"; + ctx.app.middleware.log('../../controllerLog', blockName + ">>>>" + error); + this.setResponse(ctx, 500, '服务器错误', "none"); + } + } +} + +module.exports = TeachingController; diff --git a/app/core/base_controller.js b/app/core/base_controller.js new file mode 100644 index 0000000..50a4d70 --- /dev/null +++ b/app/core/base_controller.js @@ -0,0 +1,110 @@ +const { Controller } = require('egg'); + +const sha256 = require("crypto-js/sha256"); + +const CryptoJS = require("crypto-js"); + +const KEY = CryptoJS.enc.Utf8.parse('BDQH'); + +class BaseController extends Controller { + shaForm = (body, salt) => { + return sha256(sha256(body).toString() + salt).toString(); + } + + encryptRequest = (body) => { + return CryptoJS.AES.encrypt(body, KEY, { + mode: CryptoJS.mode.ECB, + padding: CryptoJS.pad.Pkcs7 + }).toString(); + } + + decryptRequest = (body) => { + return CryptoJS.AES.decrypt(body, KEY, { + mode: CryptoJS.mode.ECB, + padding: CryptoJS.pad.Pkcs7 + }).toString(CryptoJS.enc.Utf8); + } + + checkUid = async (ctx, uid) => { + const token = ctx.request.header.authorization; + const redis = ctx.app.redis; + let rdmcode; + if (!uid) { + const [buser, cuser] = await Promise.all([ + redis.get('db0').get(token), + redis.get('db1').get(token), + ]); + rdmcode = buser || cuser; + } else { + const redisType = { + "B": "db0", + "C": "db1" + }; + const lastCode = uid[uid.length - 1]; + rdmcode = await redis.get(redisType[lastCode]).get(token); + } + if (!rdmcode) { + return false; + } + return rdmcode; + }; + + setResponse = (ctx, code, msg, model, data = {}) => { + const modelType = { + "none": { code, msg }, + "deconstruction": { code, msg, ...data }, + "polymerization": { code, msg, data } + } + ctx.body = modelType[model]; + } + + // 黑名单管理器 + banManager = async (redis, token) => { + // 基本元素 + const now = new Date().getTime(); + let reex = 1209600; + let tokenContainer = await redis.get('db4').get('tokenContainer'); + let tokenCheck = await redis.get('db4').get(token); + let ex = await redis.get('db4').ttl(token); + tokenCheck = JSON.parse(tokenCheck); + // 判断存放教学接口 token 的容器是否存在,不存在则创建并设置过期时间 + if (!tokenContainer == null) { + reex = await redis.get('db4').ttl('tokenContainer'); + if (reex <= 600) { + reex = 1209600; + await redis.get('db4').set('tokenContainer', JSON.stringify(JSON.parse(tokenContainer)), 'EX', reex); + } + } else { + let createContainer = {}; + createContainer[token] = { num: 1, firstTime: now }; + await redis.get('db4').set('tokenContainer', JSON.stringify(createContainer), 'EX', reex); + } + tokenContainer = JSON.parse(tokenContainer); + if (tokenContainer !== null && tokenCheck !== null) { + // 黑名单回收器 + for (let item in tokenContainer) { + if (tokenContainer[item].firstTime < now - 1000) { + delete tokenContainer[item]; + } + } + // 黑名单释放器 + if (tokenCheck.attacksMark && now - tokenCheck.banAt > 3600000) { + await redis.get('db4').set(token, JSON.stringify({ uid: tokenCheck.uid, attacksMark: false }), 'EX', ex); + } + // 黑名单检查器 + if (!tokenContainer[token]) { + tokenContainer[token] = { num: 1, firstTime: now } + } else { + tokenContainer[token].num += 1; + if (tokenContainer[token].num > 10) { + delete tokenContainer[token]; + // 黑名单标记器 + await redis.get('db4').set(token, JSON.stringify({ uid: tokenCheck.uid, attacksMark: true, banAt: now }), 'EX', ex); + } + } + await redis.get('db4').set('tokenContainer', JSON.stringify(tokenContainer), 'EX', reex); + } + } +} + +module.exports = BaseController; \ No newline at end of file diff --git a/app/core/base_service.js b/app/core/base_service.js new file mode 100644 index 0000000..3872c6e --- /dev/null +++ b/app/core/base_service.js @@ -0,0 +1,85 @@ +const { Service } = require('egg'); + +const sha256 = require("crypto-js/sha256"); + +const CryptoJS = require("crypto-js"); + +const KEY = CryptoJS.enc.Utf8.parse('BDQH'); + +class BaseService extends Service { + shaForm = (body, salt) => { + return sha256(sha256(body).toString() + salt).toString(); + } + + encryptRequest = (body) => { + return CryptoJS.AES.encrypt(body, KEY, { + mode: CryptoJS.mode.ECB, + padding: CryptoJS.pad.Pkcs7 + }).toString(); + } + + decryptRequest = (body) => { + return CryptoJS.AES.decrypt(body, KEY, { + mode: CryptoJS.mode.ECB, + padding: CryptoJS.pad.Pkcs7 + }).toString(CryptoJS.enc.Utf8); + } + + // 随机盐生成函数 + generateRandomString = () => { + const lowerCaseLetters = 'abcdefghijklmnopqrstuvwxyz'; + const upperCaseLetters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'; + const numbers = '0123456789'; + + let result = ''; + + // 生成5位随机小写字母 + for (let i = 0; i < 5; i++) { + const randomIndex = Math.floor(Math.random() * lowerCaseLetters.length); + result += lowerCaseLetters[randomIndex]; + } + + // 生成5位随机大写字母 + for (let i = 0; i < 5; i++) { + const randomIndex = Math.floor(Math.random() * upperCaseLetters.length); + result += upperCaseLetters[randomIndex]; + } + + // 生成2位随机数字 + for (let i = 0; i < 2; i++) { + const randomIndex = Math.floor(Math.random() * numbers.length); + result += numbers[randomIndex]; + } + + // 打乱整个字符串 + const characters = result.split(''); + for (let i = characters.length - 1; i > 0; i--) { + const j = Math.floor(Math.random() * (i + 1)); + [characters[i], characters[j]] = [characters[j], characters[i]]; + } + + return characters.join(''); + } + + // 教学接口 token 验证,验证 token 是否存在,是否在黑名单中 + Verify = async (redis, teachingToken) => { + const token = await redis.get('db4').get(teachingToken); + if (!token) { + return 401; + } else if (JSON.parse(token).attacksMark) { + return 403; + } + return JSON.parse(token).uid; + } + + shunt = (uid) => { + return uid[uid.length - 1]; + } + + isAllDigits = (str) => { + const regex = /^\d+$/; + return regex.test(str); + } +} + +module.exports = BaseService; \ No newline at end of file diff --git a/app/middleware/log.js b/app/middleware/log.js new file mode 100644 index 0000000..6d7323a --- /dev/null +++ b/app/middleware/log.js @@ -0,0 +1,72 @@ +// 错误日志 +const fs = require('fs'); +const os = require('os'); +const path = require('path'); + +const dirCheck = (dirPath) => { + // 检查文件夹是否存在 + fs.access(dirPath, fs.constants.F_OK, (err) => { + if (err) { + // 文件夹不存在 + console.log('文件夹不存在,正在创建...'); + fs.mkdir(dirPath, { recursive: true }, (err) => { + if (err) throw err; + console.log('文件夹已创建'); + }); + } else { + // 文件夹存在 + console.log('文件夹已存在'); + } + }); +} + +module.exports = (filePath, msg) => { + // 获取时间 + let now = new Date(), + times = { + year: now.getFullYear(), + month: now.getMonth() + 1, + day: now.getDate(), + hour: now.getHours(), + minute: now.getMinutes(), + second: now.getSeconds() + }; + // 获取操作系统类型 + const type = os.type(); + console.log(`操作系统类型: ${type}`); + filePath = path.join(__dirname, filePath); + dirCheck(filePath); + const yearPath = filePath + '/' + times.year; + dirCheck(yearPath); + const monthPath = yearPath + '/' + times.month; + dirCheck(monthPath); + const dayPath = monthPath + '/' + times.day + '.txt'; + const logTime = '[' + times.year + '-' + times.month + '-' + times.day + '>>>' + times.hour + ':' + times.minute + ':' + times.second + ']' + '>>>'; + let crlf; + // 判断操作系统类型,设置换行符 + if (type === 'Windows_NT') { + crlf = '\n'; + } else { + crlf = '\r\n'; + } + // 读取文件内容 + fs.readFile(dayPath, 'utf8', (err, data) => { + if (err) { + if (err.code === 'ENOENT') { + // 文件不存在,直接写入新内容(这里实际上还是使用了覆盖的方式) + fs.writeFile(dayPath, logTime + msg + crlf, (err) => { + if (err) throw err; + console.log('文件已创建并写入新内容'); + }); + } else { + throw err; + } + } else { + // 文件存在,追加新内容 + fs.appendFile(dayPath, logTime + msg + crlf, (err) => { + if (err) throw err; + console.log('新内容已追加到文件'); + }); + } + }); +}; \ No newline at end of file diff --git a/app/model/BShortMsg.js b/app/model/BShortMsg.js new file mode 100644 index 0000000..0a7cee8 --- /dev/null +++ b/app/model/BShortMsg.js @@ -0,0 +1,24 @@ +'use strict'; + +module.exports = (app) => { + const { INTEGER, CHAR, TEXT, DATE } = app.Sequelize; + + const BShortMsg = app.model.define('bshort-msg', { + id: { type: INTEGER(11), primaryKey: true, autoIncrement: true }, + user_uid: CHAR(15), + card_id: CHAR(8), + receiver_address: CHAR(8), + original_msg: TEXT, + send_type: INTEGER(1), + encode_type: INTEGER(1), + msg_data: TEXT, + created_at: DATE, + },{ + freezeTableName: true, + timestamp: true, + createdAt: true, + updatedAt: false, + }); + + return BShortMsg; +}; \ No newline at end of file diff --git a/app/model/BuserToken.js b/app/model/BuserToken.js new file mode 100644 index 0000000..8ee153e --- /dev/null +++ b/app/model/BuserToken.js @@ -0,0 +1,18 @@ +'use strict'; + +module.exports = (app) => { + const { INTEGER, CHAR } = app.Sequelize; + + const BuserToken = app.model.define('buser-token', { + id: { type: INTEGER(8), primaryKey: true, autoIncrement: true }, + user_uid: CHAR(15), + token: CHAR(64), + },{ + freezeTableName: true, + timestamp: false, + createdAt: false, + updatedAt: false, + }); + + return BuserToken; +}; \ No newline at end of file diff --git a/app/model2/CShortMsg.js b/app/model2/CShortMsg.js new file mode 100644 index 0000000..ddc4dc3 --- /dev/null +++ b/app/model2/CShortMsg.js @@ -0,0 +1,24 @@ +'use strict'; + +module.exports = (app) => { + const { INTEGER, CHAR, TEXT, DATE } = app.Sequelize; + + const CShortMsg = app.model2.define('cshort-msg', { + id: { type: INTEGER(11), primaryKey: true, autoIncrement: true }, + user_uid: CHAR(15), + card_id: CHAR(8), + receiver_address: CHAR(8), + original_msg: TEXT, + send_type: INTEGER(1), + encode_type: INTEGER(1), + msg_data: TEXT, + created_at: DATE, + },{ + freezeTableName: true, + timestamp: true, + createdAt: true, + updatedAt: false, + }); + + return CShortMsg; +}; \ No newline at end of file diff --git a/app/router.js b/app/router.js new file mode 100644 index 0000000..72fa5e5 --- /dev/null +++ b/app/router.js @@ -0,0 +1,19 @@ +/** + * @param {Egg.Application} app - egg application + */ +module.exports = async (app) => { + const { router, controller, redis } = app; + // 服务接口 + // token状态查询接口 + router.post('/tokenStatus', controller.home.tokenStatus); + // 用户获取短期token的接口 + router.post('/getUserToken', controller.home.getUserToken); + // 用户延续短期token有效时间的接口 + router.post('/lifeHold', controller.home.lifeHold); + + // 教学接口 + // 获取最近发送的一条信息 + router.get('/getMsg', controller.teaching.getMsg) + // 获取若干条历史消息 + router.get('/getHistory', controller.teaching.getHistory) +}; diff --git a/app/service/home.js b/app/service/home.js new file mode 100644 index 0000000..e20db07 --- /dev/null +++ b/app/service/home.js @@ -0,0 +1,88 @@ +'use strict'; + +const BaseService = require('../core/base_service.js'); + +const sha256 = require("crypto-js/sha256"); + +const fileName = "home"; + +class HomeService extends BaseService { + // token 状态查询接口 + async tokenStatus(uid) { + const { ctx } = this; + const redis = ctx.app.redis; + try { + let result = {}; + const tokenUser = await redis.get('db4').get(uid); + if (!tokenUser) { + const where = { user_uid: uid }; + const attributes = ['token']; + result.remainder = false; + result.token = await ctx.model.BuserToken.findOne({ attributes, where }); + result.type = result.token == null ? 'none' : "long"; + } else { + result.remainder = await redis.get('db4').ttl(uid); + result.token = JSON.parse(tokenUser).token; + result.type = JSON.parse(tokenUser).lifeHold ? "lifeHold" : "short"; + } + const token = await redis.get('db4').get(result.token); + if(token) { + result.attacksMark = JSON.parse(token).attacksMark; + result.banAt = result.attacksMark ? JSON.parse(token).banAt : 0; + } + return result ? result : false; + } catch (error) { + const blockName = fileName + "--" + "tokenStatus"; + ctx.app.middleware.log('../../serviceLog', blockName + ">>>>" + error); + return 'error'; + } + } + + // 用户获取短期 token 的接口 + async getUserToken(uid) { + const { ctx } = this; + const redis = ctx.app.redis; + try { + const token = this.shaForm(uid, this.generateRandomString()); + const checkUser = await redis.get('db4').get(uid); + let tokenUser, tokenMark; + if (!checkUser) { + const where = { user_uid: uid }; + const attributes = ['token']; + const result = await ctx.model.BuserToken.findOne({ attributes, where }); + if (result == null) { + // 设置过期时间为一周 + tokenUser = await redis.get('db4').set(uid, JSON.stringify({ token, lifeHold: false }), 'EX', 604800); + tokenMark = await redis.get('db4').set(token, JSON.stringify({ uid, attacksMark: false }), 'EX', 604800); + } + } + return tokenUser && tokenMark ? true : false; + } catch (error) { + const blockName = fileName + "--" + "getUserToken"; + ctx.app.middleware.log('../../serviceLog', blockName + ">>>>" + error); + return 'error'; + } + } + + // 用户延续短期 token 有效时间的接口 + async lifeHold(uid) { + const { ctx } = this; + const redis = ctx.app.redis; + try { + const user = await redis.get('db4').get(uid); + let tokenUser, tokenMark; + if (!JSON.parse(user).lifeHold) { + let ex = await redis.get('db4').ttl(uid) + 604800; + tokenUser = await redis.get('db4').set(uid, JSON.stringify({ token: JSON.parse(user).token, lifeHold: true }), 'EX', ex); + tokenMark = await redis.get('db4').expire(JSON.parse(user).token, ex); + } + return tokenUser && tokenMark ? true : false; + } catch (error) { + const blockName = fileName + "--" + "lifeHold"; + ctx.app.middleware.log('../../serviceLog', blockName + ">>>>" + error); + return 'error'; + } + } +} + +module.exports = HomeService; \ No newline at end of file diff --git a/app/service/teaching.js b/app/service/teaching.js new file mode 100644 index 0000000..a0d0f61 --- /dev/null +++ b/app/service/teaching.js @@ -0,0 +1,100 @@ +'use strict'; + +const BaseService = require('../core/base_service.js'); + +const fileName = "teaching"; + +class TeachingService extends BaseService { + // 获取最近发送的一条信息 + async getMsg(redis, token) { + const { ctx } = this; + try { + const verifyResult = await this.Verify(redis, token); + let result = { code: verifyResult }; + if (verifyResult == 401) { + const where = { token }; + const attributes = ['token']; + const dbResult = await ctx.model.BuserToken.findOne({ attributes, where }); + result.code = dbResult ? dbResult.dataValus.user_uid : 401; + } + if (result.code !== 401 && result.code !== 403) { + const uidLastCode = this.shunt(result.code); + const model = { + "B": ctx.model.BShortMsg, + "C": ctx.model2.CShortMsg + }; + const attributes = ['card_id', 'encode_type', 'msg_data', 'created_at']; + const where = { user_uid: result.code }; + const limit = 1; + const order = [['created_at', 'DESC']]; + const dbOptions = { attributes, limit, order, where }; + const dbResult = await model[uidLastCode].findOne(dbOptions); + if (dbResult) { + result.userData = dbResult.dataValues; + result.code = 200; + } else { + result.code = false; + } + } + return result.code ? result : false; + } catch (error) { + const blockName = fileName + "--" + "getMsg"; + ctx.app.middleware.log('../../serviceLog', blockName + ">>>>" + error); + return 'error'; + } + } + + // 获取若干条历史消息 + async getHistory(redis, token, limit, offset) { + const { ctx } = this; + try { + const verifyResult = await this.Verify(redis, token); + let result = { code: verifyResult }; + if (verifyResult == 401) { + const where = { token }; + const attributes = ['token']; + const dbResult = await ctx.model.BuserToken.findOne({ attributes, where }); + result.code = dbResult ? dbResult.dataValus.user_uid : 401; + } + if (result.code !== 401 && result.code !== 403) { + const uidLastCode = this.shunt(result.code); + const model = { + "B": ctx.model.BShortMsg, + "C": ctx.model2.CShortMsg + }; + const attributes = ['card_id', 'encode_type', 'msg_data', 'created_at']; + const where = { user_uid: result.code }; + const order = [['created_at', 'DESC']]; + if (limit == undefined || !this.isAllDigits(limit)) { + limit = 10 + } else { + limit = parseInt(limit); + } + if (offset == undefined || !this.isAllDigits(offset)) { + offset = 1 + } else { + offset = parseInt(offset); + } + offset = (offset - 1) * limit; + const dbOptions = { attributes, limit, offset, order, where }; + const dbResult = await model[uidLastCode].findAndCountAll(dbOptions); + if (dbResult.rows.length !== 0) { + result.userData = { + rows: dbResult.rows, + count: dbResult.count + }; + result.code = 200; + } else { + result.code = false; + } + } + return result.code ? result : false; + } catch (error) { + const blockName = fileName + "--" + "getHistory"; + ctx.app.middleware.log('../../serviceLog', blockName + ">>>>" + error); + return 'error'; + } + } +} + +module.exports = TeachingService; \ No newline at end of file diff --git a/config/config.default.js b/config/config.default.js new file mode 100644 index 0000000..3b5233e --- /dev/null +++ b/config/config.default.js @@ -0,0 +1,171 @@ +/* eslint valid-jsdoc: "off" */ + +/** + * @param {Egg.EggAppInfo} appInfo app info + */ +module.exports = appInfo => { + /** + * built-in config + * @type {Egg.EggAppConfig} + **/ + const config = exports = {}; + + // use for cookie sign key, should change to your own and keep security + config.keys = appInfo.name + '_1715070383253_5684'; + + // add your middleware config here + // config.middleware = []; + + config.security = { + csrf:{ + enable:false + }, + }; + + config.redis = { + // 开发/测试环境 + clients: { + db0: { + port: 6379, + host: '127.0.0.1', + password: '74191221', + db: 0, + }, + db1: { + port: 6379, + host: '127.0.0.1', + password: '74191221', + db: 1, + }, + db2: { + port: 6379, + host: '127.0.0.1', + password: '74191221', + db: 2, + }, + db3: { + port: 6379, + host: '127.0.0.1', + password: '74191221', + db: 3, + }, + db4: { + port: 6379, + host: '127.0.0.1', + password: '74191221', + db: 4 + } + } + + // 生产环境 + // clients: { + // db0: { + // port: 6379, + // host: '127.0.0.1', + // password: 'bd3@htcc2023', + // db: 2, + // }, + // db1: { + // port: 6379, + // host: '127.0.0.1', + // password: 'bd3@htcc2023', + // db: 3, + // }, + // db2: { + // port: 6379, + // host: '127.0.0.1', + // password: 'bd3@htcc2023', + // db: 4, + // }, + // db3: { + // port: 6379, + // host: '127.0.0.1', + // password: 'bd3@htcc2023', + // db: 5, + // }, + // db4: { + // port: 6379, + // host: '127.0.0.1', + // password: 'bd3@htcc2023', + // db: 6 + // } + // } + }; + + config.sequelize = { + // 开发/测试环境 + datasources: [ + { + dialect: 'mariadb', + host: 'localhost', + port: 3306, + username: 'root', + password: '74191221', + database: 'bside', + }, + { + dialect: 'mariadb', + host: 'localhost', + port: 3306, + username: 'root', + password: '74191221', + database: 'cside', + delegate: 'model2', + baseDir: 'model2', + }, + { + dialect: 'mariadb', + host: 'localhost', + port: 3306, + username: 'root', + password: '74191221', + database: 'insiders', + delegate: 'model3', + baseDir: 'model3', + } + ] + + // 生产环境 + // datasources: [ + // { + // dialect: 'mariadb', + // host: 'localhost', + // port: 3306, + // username: 'bdqh_platform', + // password: '124689@XXxx', + // database: 'bside', + // }, + // { + // dialect: 'mariadb', + // host: 'localhost', + // port: 3306, + // username: 'bdqh_platform', + // password: '124689@XXxx', + // database: 'cside', + // delegate: 'model2', + // baseDir: 'model2', + // }, + // { + // dialect: 'mariadb', + // host: 'localhost', + // port: 3306, + // username: 'bdqh_platform', + // password: '124689@XXxx', + // database: 'insiders', + // delegate: 'model3', + // baseDir: 'model3', + // } + // ] + }; + + // add your user config here + const userConfig = { + // myAppName: 'egg', + salt:'teachingApi' + }; + + return { + ...config, + ...userConfig, + }; +}; diff --git a/config/plugin.js b/config/plugin.js new file mode 100644 index 0000000..5a65fbe --- /dev/null +++ b/config/plugin.js @@ -0,0 +1,22 @@ +/** @type Egg.EggPlugin */ +module.exports = { + // had enabled by egg + // static: { + // enable: true, + // } + + redis : { + enable: true, + package: 'egg-redis', + }, + + sequelize : { + enable: true, + package: 'egg-sequelize', + }, + + validate : { + enable: true, + package: 'egg-validate', + }, +}; diff --git a/controllerLog/2025/2/11.txt b/controllerLog/2025/2/11.txt new file mode 100644 index 0000000..afcffe2 --- /dev/null +++ b/controllerLog/2025/2/11.txt @@ -0,0 +1 @@ +[2025-2-11>>>10:34:39]>>>home--tokenStatus>>>>ReferenceError: decryptRequest is not defined diff --git a/controllerLog/2025/2/12.txt b/controllerLog/2025/2/12.txt new file mode 100644 index 0000000..3b4f6da --- /dev/null +++ b/controllerLog/2025/2/12.txt @@ -0,0 +1 @@ +[2025-2-12>>>14:51:56]>>>teaching--getMsg>>>>TypeError: Cannot read properties of undefined (reading 'code') diff --git a/controllerLog/2025/2/13.txt b/controllerLog/2025/2/13.txt new file mode 100644 index 0000000..aa1b240 --- /dev/null +++ b/controllerLog/2025/2/13.txt @@ -0,0 +1,3 @@ +[2025-2-13>>>10:45:5]>>>home--lifeHold>>>>TypeError: Cannot read properties of undefined (reading 'ciphertext') +[2025-2-13>>>10:45:5]>>>home--lifeHold>>>>TypeError: Cannot read properties of undefined (reading 'ciphertext') +[2025-2-13>>>17:40:44]>>>home--tokenStatus>>>>TypeError: Cannot read properties of undefined (reading 'ciphertext') diff --git a/controllerLog/2025/2/14.txt b/controllerLog/2025/2/14.txt new file mode 100644 index 0000000..12cacc1 --- /dev/null +++ b/controllerLog/2025/2/14.txt @@ -0,0 +1,8 @@ +[2025-2-14>>>9:13:32]>>>home--tokenStatus>>>>TypeError: Cannot read properties of undefined (reading 'ciphertext') +[2025-2-14>>>9:44:31]>>>home--tokenStatus>>>>TypeError: Cannot read properties of undefined (reading 'ciphertext') +[2025-2-14>>>9:45:10]>>>home--tokenStatus>>>>ReferenceError: Cannot access 'uid' before initialization +[2025-2-14>>>9:45:28]>>>home--tokenStatus>>>>TypeError: Cannot read properties of undefined (reading 'ciphertext') +[2025-2-14>>>9:58:56]>>>home--tokenStatus>>>>TypeError: Cannot read properties of undefined (reading 'ciphertext') +[2025-2-14>>>10:2:39]>>>home--tokenStatus>>>>TypeError: Cannot read properties of undefined (reading 'ciphertext') +[2025-2-14>>>15:52:39]>>>teaching--getHistory>>>>TypeError: Cannot read properties of undefined (reading 'rows') +[2025-2-14>>>15:52:41]>>>teaching--getHistory>>>>TypeError: Cannot read properties of undefined (reading 'rows') diff --git a/database/config.json b/database/config.json new file mode 100644 index 0000000..1b65e53 --- /dev/null +++ b/database/config.json @@ -0,0 +1,23 @@ +{ + "development": { + "username": "root", + "password": 74191221, + "database": "vm_centos", + "host": "127.0.0.1", + "dialect": "mariadb" + }, + "test": { + "username": "root", + "password": 74191221, + "database": "vm_centos", + "host": "127.0.0.1", + "dialect": "mariadb" + }, + "production": { + "username": "root", + "password": 74191221, + "database": "vm_centos", + "host": "127.0.0.1", + "dialect": "mariadb" + } +} diff --git a/jsconfig.json b/jsconfig.json new file mode 100644 index 0000000..1bbed3f --- /dev/null +++ b/jsconfig.json @@ -0,0 +1,5 @@ +{ + "include": [ + "**/*" + ] +} \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 0000000..dc0626f --- /dev/null +++ b/package.json @@ -0,0 +1,48 @@ +{ + "name": "teaching-api", + "version": "1.0.0", + "description": "", + "private": true, + "egg": { + "declarations": true + }, + "dependencies": { + "crypto-js": "^4.2.0", + "egg": "^3.17.5", + "egg-redis": "^2.6.0", + "egg-scripts": "2", + "egg-sequelize": "^6.0.0", + "egg-validate": "^2.0.2", + "ioredis": "^5.4.1", + "mariadb": "^3.3.0", + "mysql2": "^3.9.7", + "sequelize": "^6.37.3", + "teaching-api": "file:" + }, + "devDependencies": { + "egg-bin": "6", + "egg-mock": "5", + "eslint": "8", + "eslint-config-egg": "13", + "sequelize-cli": "^6.6.2" + }, + "engines": { + "node": ">=16.0.0" + }, + "scripts": { + "start": "egg-scripts start --daemon --port=8017 --title=egg-server-teaching-api", + "stop": "egg-scripts stop --title=egg-server-teaching-api", + "dev": "egg-bin dev --port=8017", + "test": "npm run lint -- --fix && npm run test:local", + "test:local": "egg-bin test", + "cov": "egg-bin cov", + "lint": "eslint .", + "ci": "npm run lint && npm run cov" + }, + "repository": { + "type": "git", + "url": "" + }, + "author": "", + "license": "MIT" +} diff --git a/serviceLog/2025/2/11.txt b/serviceLog/2025/2/11.txt new file mode 100644 index 0000000..b2abc8e --- /dev/null +++ b/serviceLog/2025/2/11.txt @@ -0,0 +1,2 @@ +[2025-2-11>>>14:31:25]>>>home--lifeHold>>>>SyntaxError: Unexpected token o in JSON at position 1 +[2025-2-11>>>14:39:36]>>>home--tokenStatus>>>>SyntaxError: Unexpected token o in JSON at position 1 diff --git a/serviceLog/2025/2/12.txt b/serviceLog/2025/2/12.txt new file mode 100644 index 0000000..c725bcb --- /dev/null +++ b/serviceLog/2025/2/12.txt @@ -0,0 +1,19 @@ +[2025-2-12>>>14:41:26]>>>teaching--getMsg>>>>Error: WHERE parameter "token" has invalid "undefined" value +[2025-2-12>>>14:41:28]>>>teaching--getHistory>>>>Error: WHERE parameter "token" has invalid "undefined" value +[2025-2-12>>>14:48:1]>>>teaching--getMsg>>>>ReferenceError: dbOptions is not defined +[2025-2-12>>>15:13:29]>>>teaching--getHistory>>>>SequelizeDatabaseError: (conn:192, no: 1064, SQLState: 42000) You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near ''10'' at line 1 +sql: SELECT `card_id`, `encode_type`, `msg_data`, `created_at` FROM `bshort-msg` AS `bshort-msg` WHERE `bshort-msg`.`user_uid` = '20240613698218B' ORDER BY `bshort-msg`.`created_at` DESC LIMIT 0, '10'; - parameters:[] +[2025-2-12>>>15:20:23]>>>teaching--getHistory>>>>SequelizeDatabaseError: (conn:206, no: 1064, SQLState: 42000) You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near ''10'' at line 1 +sql: SELECT `card_id`, `encode_type`, `msg_data`, `created_at` FROM `bshort-msg` AS `bshort-msg` WHERE `bshort-msg`.`user_uid` = '20240613698218B' ORDER BY `bshort-msg`.`created_at` DESC LIMIT 0, '10'; - parameters:[] +[2025-2-12>>>15:21:54]>>>teaching--getHistory>>>>SequelizeDatabaseError: (conn:217, no: 1064, SQLState: 42000) You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near ''1', '10'' at line 1 +sql: SELECT `card_id`, `encode_type`, `msg_data`, `created_at` FROM `bshort-msg` AS `bshort-msg` WHERE `bshort-msg`.`user_uid` = '20240613698218B' ORDER BY `bshort-msg`.`created_at` DESC LIMIT '1', '10'; - parameters:[] +[2025-2-12>>>15:23:34]>>>teaching--getHistory>>>>SequelizeDatabaseError: (conn:224, no: 1064, SQLState: 42000) You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near ''1', '10'' at line 1 +sql: SELECT `card_id`, `encode_type`, `msg_data`, `created_at` FROM `bshort-msg` AS `bshort-msg` WHERE `bshort-msg`.`user_uid` = '20240613698218B' ORDER BY `bshort-msg`.`created_at` DESC LIMIT '1', '10'; - parameters:[] +[2025-2-12>>>15:31:9]>>>teaching--getHistory>>>>SequelizeDatabaseError: (conn:231, no: 1064, SQLState: 42000) You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near ''10'' at line 1 +sql: SELECT `card_id`, `encode_type`, `msg_data`, `created_at` FROM `bshort-msg` AS `bshort-msg` WHERE `bshort-msg`.`user_uid` = '20240613698218B' ORDER BY `bshort-msg`.`created_at` DESC LIMIT 0, '10'; - parameters:[] +[2025-2-12>>>15:33:6]>>>teaching--getHistory>>>>SequelizeDatabaseError: (conn:252, no: 1064, SQLState: 42000) You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near ''10'' at line 1 +sql: SELECT `card_id`, `encode_type`, `msg_data`, `created_at` FROM `bshort-msg` AS `bshort-msg` WHERE `bshort-msg`.`user_uid` = '20240613698218B' ORDER BY `bshort-msg`.`created_at` DESC LIMIT '10'; - parameters:[] +[2025-2-12>>>16:22:32]>>>home--lifeHold>>>>TypeError: Cannot read properties of null (reading 'lifeHold') +[2025-2-12>>>16:24:2]>>>home--lifeHold>>>>TypeError: Cannot read properties of null (reading 'lifeHold') +[2025-2-12>>>16:24:38]>>>home--lifeHold>>>>TypeError: Cannot read properties of null (reading 'lifeHold') +[2025-2-12>>>16:25:0]>>>home--lifeHold>>>>TypeError: Cannot read properties of null (reading 'lifeHold')