Skip to content
This repository has been archived by the owner on Apr 16, 2024. It is now read-only.

新增eapi算法 #491

Merged
merged 5 commits into from
May 16, 2019
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions module/batch.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
module.exports = (query, request) => {
const data = {
"e_r": true
};
Object.keys(query).forEach(i => {
if (/^\/api\//.test(i)) {
data[i] = query[i]
}
})
return request(
'POST', `http://music.163.com/eapi/batch`, data,
{crypto: 'eapi', proxy: query.proxy, url: '/api/batch', cookie: query.cookie}
)
};
18 changes: 17 additions & 1 deletion util/crypto.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ const presetKey = Buffer.from('0CoJUm6Qyw8W8jud')
const linuxapiKey = Buffer.from('rFgB&h#%2?^eDg:Q')
const base62 = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
const publicKey = '-----BEGIN PUBLIC KEY-----\nMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDgtQn2JZ34ZC28NWYpAUd98iZ37BUrX/aKzmFbt7clFSs6sXqHauqKWqdtLkF2KexO40H1YTX8z2lSgBBOAxLsvaklV8k4cBFK9snQXE9/DDaFt6Rr7iVZMldczhC0JNgTz+SHXT6CBHuX3e9SdB1Ua44oncaTWz7OBGLbCiK45wIDAQAB\n-----END PUBLIC KEY-----'
const eapiKey = 'e82ckenh8dichen8'

const aesEncrypt = (buffer, mode, key, iv) => {
const cipher = crypto.createCipheriv('aes-128-' + mode, key, iv)
Expand Down Expand Up @@ -31,4 +32,19 @@ const linuxapi = (object) => {
}
}

module.exports = {weapi, linuxapi}
const eapi = (url, object) => {
const text = typeof object === 'object' ? JSON.stringify(object) : object;
const message = `nobody${url}use${text}md5forencrypt`
const digest = crypto.createHash('md5').update(message).digest('hex')
const data = `${url}-36cd479b6b5-${text}-36cd479b6b5-${digest}`
return {
params: aesEncrypt(Buffer.from(data), 'ecb', eapiKey, '').toString('hex').toUpperCase()
}
}

const decrypt = cipherBuffer => {
const decipher = crypto.createDecipheriv('aes-128-ecb',eapiKey,'')
return Buffer.concat([decipher.update(cipherBuffer), decipher.final()])
}

module.exports = {weapi, linuxapi, eapi, decrypt}
75 changes: 68 additions & 7 deletions util/request.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ const encrypt = require('./crypto')
const request = require('request')
const queryString = require('querystring')
const PacProxyAgent = require('pac-proxy-agent')
const zlib = require('zlib')

// request.debug = true // 开启可看到更详细信息

Expand All @@ -25,16 +26,16 @@ const chooseUserAgent = ua => {
let index = 0
if (typeof ua == 'undefined')
index = Math.floor(Math.random() * userAgentList.length)
else if (ua == 'mobile') index = Math.floor(Math.random() * 7)
else if (ua == 'pc') index = Math.floor(Math.random() * 5) + 8
else if (ua === 'mobile') index = Math.floor(Math.random() * 7)
else if (ua === 'pc') index = Math.floor(Math.random() * 5) + 8
else return ua
return userAgentList[index]
}

const createRequest = (method, url, data, options) => {
return new Promise((resolve, reject) => {
let headers = { 'User-Agent': chooseUserAgent(options.ua) }
if (method.toUpperCase() == 'POST')
if (method.toUpperCase() === 'POST')
headers['Content-Type'] = 'application/x-www-form-urlencoded'
if (url.includes('music.163.com'))
headers['Referer'] = 'https://music.163.com'
Expand All @@ -51,12 +52,12 @@ const createRequest = (method, url, data, options) => {
.join('; ')
else if (options.cookie) headers['Cookie'] = options.cookie

if (options.crypto == 'weapi') {
if (options.crypto === 'weapi') {
let csrfToken = (headers['Cookie'] || '').match(/_csrf=([^(;|$)]+)/)
data.csrf_token = csrfToken ? csrfToken[1] : ''
data = encrypt.weapi(data)
url = url.replace(/\w*api/, 'weapi')
} else if (options.crypto == 'linuxapi') {
} else if (options.crypto === 'linuxapi') {
data = encrypt.linuxapi({
method: method,
url: url.replace(/\w*api/, 'api'),
Expand All @@ -65,6 +66,35 @@ const createRequest = (method, url, data, options) => {
headers['User-Agent'] =
'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36'
url = 'https://music.163.com/api/linux/forward'
} else if (options.crypto === 'eapi') {
const cookie = options.cookie || {};
const csrfToken = cookie['__csrf'] || ''
const header = {
"osver": cookie.osver, //系统版本
"deviceId": cookie.deviceId, //encrypt.base64.encode(imei + '\t02:00:00:00:00:00\t5106025eb79a5247\t70ffbaac7')
"appver": cookie.appver || "6.1.1", // app版本
"versioncode": cookie.versioncode || "140", //版本号
"mobilename": cookie.mobilename, //设备model
"buildver": cookie.buildver || Date.now().toString().substr(0, 10),
"resolution": cookie.resolution || "1920x1080", //设备分辨率
"__csrf": csrfToken,
"os": cookie.os || 'android',
"channel": cookie.channel,
"requestId":`${Date.now()}_${Math.floor(Math.random() * 1000).toString().padStart(4, '0')}`
}
if (cookie.MUSIC_U) header["MUSIC_U"] = cookie.MUSIC_U
if (cookie.MUSIC_A) header["MUSIC_A"] = cookie.MUSIC_A
headers['Cookie'] = Object.keys(header)
.map(
key =>
encodeURIComponent(key) +
'=' +
encodeURIComponent(header[key])
)
.join('; ')
data.header = header
data = encrypt.eapi(options.url, data)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

options.url 是什么鬼==

url = url.replace(/\w*api/,'eapi')
}

const answer = { status: 500, body: {}, cookie: [] }
Expand All @@ -75,6 +105,8 @@ const createRequest = (method, url, data, options) => {
body: queryString.stringify(data)
}

if (options.crypto === 'eapi') settings.encoding = null

if (/\.pac$/i.test(options.proxy)) {
settings.agent = new PacProxyAgent(options.proxy)
} else {
Expand All @@ -93,12 +125,41 @@ const createRequest = (method, url, data, options) => {
x.replace(/\s*Domain=[^(;|$)]+;*/, '')
)
try {
answer.body = JSON.parse(body)
answer.status = answer.body.code || res.statusCode
if (options.crypto === 'eapi') {

zlib.unzip(body, function (err, buffer) {
const _buffer = err ? body : buffer
try {
try{
answer.body = JSON.parse(encrypt.decrypt(_buffer).toString())
answer.status = answer.body.code || res.statusCode
} catch(e){
answer.body = JSON.parse(_buffer.toString())
answer.status = res.statusCode
}
} catch (e) {
answer.body = _buffer.toString()
answer.status = res.statusCode
}
answer.status =
100 < answer.status && answer.status < 600 ? answer.status : 400
if (answer.status === 200) resolve(answer)
else reject(answer)
});
return false

} else {

answer.body = JSON.parse(body)
answer.status = answer.body.code || res.statusCode

}

} catch (e) {
answer.body = body
answer.status = res.statusCode
}

answer.status =
100 < answer.status && answer.status < 600 ? answer.status : 400
if (answer.status == 200) resolve(answer)
Expand Down