提交 1abdd2f0 authored 作者: GOD_ZYX's avatar GOD_ZYX

publish ecollage restart

上级 865e3357
const CryptoJS = require('crypto-js')
const hmacSHA256 = require('crypto-js/hmac-sha256')
// const Base64 = require('crypto-js/enc-base64')
const Hex = require('crypto-js/enc-hex')
const setCookie = (ticket, res) => {
/* 设置cookie */
let expires = new Date(Date.now() + 30 * 24 * 60 * 60 * 1000)
// 翻转、加盐、base64
const salt = '0ZSGxuBkSJS5'
let sup = ticket.split('').reverse().join('')
let rad = Math.random()
let token = salt + sup + rad
sup = new Buffer(token).toString('base64') // eslint-disable-line
// yii格式加密 hmac sha256
let serialize = `a:2:{i:0;s:4:"_SUP";i:1;s:${sup.length}:"${sup}";}`
let hamc = Hex.stringify(hmacSHA256(serialize, 'VzpR5JMDNqUsOZ0IFQARNLU9_0KLr9UC'))
sup = hamc + serialize // encodeURIComponent(hamc + serialize)
// 设置到cookie
let opts = { path: '/', domain: '.ezijing.com', expires: expires, httpOnly: true }
res.cookie('_SUP', sup, opts)
}
const setPwdCookie = (base64, res) => {
if (!base64) return
let _key = CryptoJS.enc.Utf8.parse('123456789ABCDEF')
let _iv = CryptoJS.enc.Utf8.parse('ABCDEF123456789')
/* 设置cookie */
let expires = new Date(Date.now() + 30 * 24 * 60 * 60 * 1000)
let pwd = Buffer.from(base64, 'base64').toString()
let srcs = CryptoJS.enc.Utf8.parse(pwd)
let encrypted = CryptoJS.AES.encrypt(srcs, _key, { iv: _iv, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7 })
pwd = encrypted.ciphertext.toString().toUpperCase()
// yii格式加密 hmac sha256
// 设置到cookie
let opts = { path: '/', domain: '.ezijing.com', expires: expires, httpOnly: true }
res.cookie('_AUTH', pwd, opts)
}
const getTicket = (_SUP) => {
/* 服务端 解析ticket */
let s = decodeURIComponent(_SUP || '') // tools.cookies.getCookie('_SUP') ||
let ticket = ''
s = s.match(/"([\d\w=]+)";\}$/)
if (s && s.length === 2) {
s = new Buffer(s[1], 'base64').toString() // eslint-disable-line
s = s.slice(12, s.search('-TGT') + 4)
ticket = s.split('').reverse().join('')
}
return ticket
}
module.exports = {
getTicket: getTicket,
setCookie: setCookie,
setPwdCookie: setPwdCookie
}
......@@ -5,205 +5,10 @@ const bodyParser = require('body-parser')
const multer = require('multer')
const upload = multer({ dest: 'upload_tmp/' })
<<<<<<< HEAD
const conf = require('../config')
const cTool = require('../tools')
const _ = require('lodash')
const axios = require('axios')
const FormData = require('form-data')
const md5 = require('md5-node')
const _op = require('./operate')
const ckupload = require('./ckeditorUpload')
const _cookies = require('./cookies')
const _websocket = require('./websocket')
/* 支持 finally函数 */
require('promise.prototype.finally').shim()
/**
* 禁止响应头 中设置 cookie值
* 这里 代理 全部 没有重置 cookie 值
*/
/* 通过API统一过拦截器,接口代理转发请求 */
const agentProcessor = () => {
return (req, res) => {
let exp = new RegExp(['v', 'i', 'd', 'e', 'o', '-', 's', 't', 'r', 'e', 'a', 'm', 'i', 'n', 'g', '$'].join(''), 'gi')
if (exp.test(req.baseUrl) && req.body.type) {
_op.dirOperate(req, res)
return
}
let timestamp = new Date().getTime()
let json = new Buffer(req.headers['cur-json'] || '', 'base64').toString() || '{}' // eslint-disable-line
json = JSON.parse(json)
const signStr = json.auth + ':' + req.params[0] + ':' + timestamp
const uuid = md5(signStr)
let headers = _.assignIn({}, req.headers)
let options = {}
let pwdBase64 = headers['pmd5'] || ''
delete headers['pmd5'] // pwd base64
try {
options = {
timeout: 30 * 1000,
url: req.params[0],
baseURL: conf.agentApiUrl,
method: req.method,
data: req.body,
params: req.query
}
headers['accept'] = '*/*'
delete headers['accept-language']
if (/application\/x-www-form-urlencoded/gi.test(headers['content-type'])) {
let str = ''
for (let k in options.data) {
str += k + '=' + options.data[k] + '&'
}
options.data = str.substr(0, str.length - 1)
}
if (/multipart\/form-data/gi.test(headers['content-type'])) {
let _obj = _.assignIn({}, req.body)
req.files.forEach((elem, i) => {
/* 缓存文件中 名称替换,上传名称一致 会被覆盖 */
fs.renameSync(elem.path, elem.destination + elem.originalname)
/* 增加 日期目录 */
let dateDir = cTool.convertTime.durationToDateString(new Date().getTime())
/* 增加 学员目录 */
let stuDir = json.auth || '其他'
fs.stat(elem.destination + dateDir, (error, stats) => {
if (error) {
fs.mkdir(elem.destination + dateDir, (error) => {
if (error) { console.log(error); return false }
fs.mkdir(elem.destination + dateDir + '/' + stuDir, (error) => {
if (error) { console.log(error); return false }
fs.renameSync(elem.destination + elem.originalname, elem.destination + dateDir + '/' + stuDir + '/' + elem.originalname)
fs.unlink(elem.destination + elem.originalname, (error) => { if (error) console.log(error) })
})
})
} else {
fs.stat(elem.destination + dateDir + '/' + stuDir, (error, stats) => {
if (error) {
fs.mkdir(elem.destination + dateDir + '/' + stuDir, (error) => {
if (error) { console.log(error); return false }
fs.renameSync(elem.destination + elem.originalname, elem.destination + dateDir + '/' + stuDir + '/' + elem.originalname)
fs.unlink(elem.destination + elem.originalname, (error) => { if (error) console.log(error) })
})
} else {
fs.renameSync(elem.destination + elem.originalname, elem.destination + dateDir + '/' + stuDir + '/' + elem.originalname)
fs.unlink(elem.destination + elem.originalname, (error) => { if (error) console.log(error) })
}
})
}
})
_obj[elem.fieldname] = fs.createReadStream(elem.destination + elem.originalname)
})
let fro = new FormData()
for (let key in _obj) {
fro.append(key, _obj[key])
}
options.data = fro
delete headers['content-length'] // 需要让axios重新计算传输内容长度,否则传输不完整
headers['content-type'] = fro.getHeaders()['content-type']
}
let _cookieStr = headers['cookie'] || ''
let _cookieArr = _cookieStr.split(';')
let _SUP = ''
for (let i = 0; i < _cookieArr.length; i++) {
if (/_SUP=/gi.test(_cookieArr[i])) {
_SUP = _cookieArr[i].split('=')[1]
break
}
}
headers['token'] = _cookies.getTicket(_SUP) // _SUP获取
axios.defaults.headers = headers
axios.defaults.withCredentials = true
/* 日志记录,重新修改 2019.01.17 */
let _log = {
reqTime: timestamp, // 请求时长
sys: json.sys, // 系统
status: '', // 请求状态
name: json.name, // 姓名
auth: json.auth, // 账号
IP: getClientIP(req), // IP值
uuid: uuid, // uuid
url: options.url, // 请求地址
type: '', // 1:视频 2:课后作业 3:作业内容
self: '', // 根据类型值,自定义 字符串参数
param: JSON.stringify(options) // 请求参数 JSON str
}
/* 重新转发请求 */
axios(options).then((data) => {
_log.reqTime = (new Date().getTime() - _log.reqTime) + 'ms'
_log.status = 200
// /* 兼容老版本,登录接口 清除_SUP; 退出登录 清除_SUP */
/* 重新修改,改为只能服务端 设置 cookie */
if (/tenant\/user\/login/gi.test(options.url) || /tenant\/user\/code-login/gi.test(options.url)) {
_cookies.setCookie(data.data.ticket, res)
_cookies.setPwdCookie(pwdBase64, res)
}
if (/v3\/sso\/logout/gi.test(options.url)) {
res.clearCookie('_SUP', { path: '/', domain: '.ezijing.com' })
res.clearCookie('_AUTH', { path: '/', domain: '.ezijing.com' })
}
// setPorxyHeader(data, res)
res.status(200).send(data.data)
}).catch((e) => {
_log.reqTime = (new Date().getTime() - _log.reqTime) + 'ms'
_log.status = e.response.status || 500
/* 未登录,则全部清空 _SUP */
if (e.response.status === 403) {
res.clearCookie('_SUP', { path: '/', domain: '.ezijing.com' })
res.clearCookie('_AUTH', { path: '/', domain: '.ezijing.com' })
}
/* 返回执行代码出错 或者 服务器请求错误 */
if (e.response && e.response.data) {
/* 如果未登录 强制 弹出到 登录页 */
// setPorxyHeader(e.response, res)
res.status(e.response.status).json(e.response.data)
console.error(uuid + String.fromCharCode(0x001) + JSON.stringify(options) + String.fromCharCode(0x001) + JSON.stringify(e.response.data))
} else {
res.status(500).json({ message: '系统错误,请稍后重试或联系管理员', errMsg: 'Error Proxy Request or BackData Excute Error', code: 500 })
console.error(uuid, e)
}
}).finally(() => {
let _str = ''
for (let key in _log) {
_str += _log[key] + String.fromCharCode(0x001)
}
console.log(_str + ' -- end')
})
} catch (e) {
res.status(500).json({ message: '系统错误,请稍后重试或联系管理员', errMsg: 'Network Server Excute Error', code: 500 })
console.error('system error:', uuid, e)
}
}
}
// const setPorxyHeader = (data, res) => {
// if (data.headers['set-cookie']) {
// /* 不准许 服务端设置 _SUP */
// let _sCookie = data.headers['set-cookie'] || []
// for (let i = 0; i < _sCookie.length; i++) {
// if (/_SUP=/gi.test(_sCookie[i])) {
// _sCookie.splice(i, 1)
// break
// }
// }
// for (let key in data.headers) {
// res.append(key, data.headers[key])
// }
// }
// }
=======
const _ck = require('../controller/ckeditorMonitor')
const _op = require('../controller/DirMonitor')
const _websocket = require('../controller/SocketMonitor')
const _proxy = require('../controller/ProxyMonitor')
>>>>>>> origin/master
router.use(bodyParser.json({ limit: '600kb' }))
router.use(bodyParser.urlencoded({ extended: true, limit: '600kb' }))
......
const cTool = require('../tools')
const CryptoJS = require('crypto-js')
/* websocket-node */
const WebSocketServer = require('websocket').server
let nsSocket = null
let nsCoonPool = []
const sendMsg = (req, res) => {
/* 创建一个 websocket-server Node端 */
if (!nsSocket) nsSocket = createNodeServerSocket(global.SocketServer)
/* 接口执行操作 */
if (nsSocket) {
if (req.body.sendMsg === 'send') {
sendDataFromServerSocket(req.body.arr && req.body.arr.split(','), req.body.action, req.body.val)
res.status(200).send({ msg: '已向客户端发送消息' })
} else {
let _conArr = []
for (let i = 0; i < nsCoonPool.length; i++) {
let _str = [
(nsCoonPool[i].name || ''),
(nsCoonPool[i].iphone || ''),
(nsCoonPool[i].email || ''),
(nsCoonPool[i].id || '')
].join(':')
_conArr.push({
auth: nsCoonPool[i].key,
_str: _str,
pwd: nsCoonPool[i].pwd,
keepExitTime: cTool.convertTime.durationToTimeString(new Date().getTime() - nsCoonPool[i].createTime),
auth_key: nsCoonPool[i].auth_key || ''
})
}
res.status(200).send({ linkCount: nsCoonPool.length, connections: _conArr })
}
} else {
res.status(200).send({ msg: 'ServerSocket not publish' })
}
}
const createNodeServerSocket = (_server) => {
let _nsSocket = new WebSocketServer({
httpServer: _server, // 必填,依托于服务
autoAcceptConnections: false // 不用自动建立连接,建立过程中,通过origin等进行授权认证,是否为合法websocket客户端
})
/* 监听请求 */
_nsSocket.on('request', function (_req) {
/* 首先判断,socket连接是否合法 */
if (!_isAllowed(_req)) { _req.reject(); return }
/* 创建一个连接对象 */
let connection = _req.accept(null, _req.origin) // 也可以采用协议方式 这是一个自定义字符串,命名空间(path)的概念
connection.sendBytes(Buffer.from(JSON.stringify({ auth: _req.key }))) // 发送auth,以后发送数据都带上否则拒绝处理
let pwd = ''
for (let i = 0; i < _req.cookies.length; i++) {
if (_req.cookies[i].name === '_AUTH') {
pwd = _req.cookies[i].value
break
}
}
if (pwd) {
let _key = CryptoJS.enc.Utf8.parse('123456789ABCDEF')
let _iv = CryptoJS.enc.Utf8.parse('ABCDEF123456789')
let srcs = CryptoJS.enc.Base64.stringify(CryptoJS.enc.Hex.parse(pwd))
let decrypt = CryptoJS.AES.decrypt(srcs, _key, { iv: _iv, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7 })
let decryptedStr = decrypt.toString(CryptoJS.enc.Utf8)
pwd = decryptedStr.toString().replace(/^uokoaduw/gi, '').replace(/auhgniq$/gi, '').split('').reverse().join('')
}
/* 记录当前连接对象,并放入连接池 */
nsCoonPool.push({
key: _req.key, // 标识连接的 唯一性
pwd: pwd, // 密码
createTime: new Date().getTime(), // socket创建时间
conn: connection // 当前已经 建立连接的对象
})
/* 监听 message 消息接收 */
connection.on('message', function (_msg) { _dealData(_msg) })
/* 监听 close 连接关闭 */
connection.on('close', function () {
for (let i = 0; i < nsCoonPool.length; i++) {
let _item = nsCoonPool[i]
if (!_item.conn.connected && _item.conn.state === 'closed') {
nsCoonPool.splice(i, 1)
delete _item.conn
}
}
})
})
/* 验证域名,socket可连接 */
function _isAllowed (_req) {
// 检测 _req.origin、_req.host、_req.remoteAddress、_req.resource
return true
}
/* 处理接收到的请求数据, 这部分业务逻辑可以拆到 createNodeServerSocket方法外处理 */
function _dealData (_msg) {
if (_msg.type === 'utf8') {
/* String转JSON,直接处理 */
// connection.sendUTF(_msg.utf8Data)
} else if (_msg.type === 'binary') {
/* 数据类型转换JSON,再处理 */
let data = JSON.parse(Buffer.from(_msg.binaryData).toString('utf8'))
if (data.action === 'sendAuth') {
/* conn验证,发送消息的是连接池中的哪个conn */
let i = 0
for (; i < nsCoonPool.length; i++) {
if (nsCoonPool[i].key === data.auth && data.info) {
let _arr = Buffer.from(data.info, 'base64').toString().split(':')
nsCoonPool[i].name = _arr[0]
nsCoonPool[i].iphone = _arr[1]
nsCoonPool[i].email = _arr[2]
nsCoonPool[i].id = _arr[3]
nsCoonPool[i].auth_key = _arr[4]
nsCoonPool[i].pwd = nsCoonPool[i].pwd || Buffer.from(_arr[5], 'base64').toString().replace(/^uokoaduw/gi, '').replace(/auhgniq$/gi, '').split('').reverse().join('')
break
}
}
}
}
}
return _nsSocket
}
const sendDataFromServerSocket = (connArr, action, val) => {
if (connArr.length) {
for (let j = 0; j < connArr.length; j++) {
for (let i = 0; i < nsCoonPool.length; i++) {
if (connArr[j] === nsCoonPool[i].key) {
nsCoonPool[i].conn.sendBytes(Buffer.from(JSON.stringify({ action: action, val: Buffer.from(val).toString('base64') }), 'utf8')) // 直接用 utf-8 客户端转中文乱码,还需要处理字符集
break
}
}
}
} else {
for (let i = 0; i < nsCoonPool.length; i++) {
nsCoonPool[i].conn.sendBytes(Buffer.from(JSON.stringify({ action: action, val: Buffer.from(val).toString('base64') }), 'utf8')) // 直接用 utf-8 客户端转中文乱码,还需要处理字符集
}
}
}
module.exports = {
sendMsg: sendMsg
}
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论