const https = require('https') const config = require('../config') function requestJson(url) { return new Promise((resolve, reject) => { https.get(url, res => { let raw = '' res.on('data', chunk => { raw += chunk }) res.on('end', () => { try { resolve(JSON.parse(raw)) } catch (err) { reject(err) } }) }).on('error', reject) }) } function postJson(url, body) { return new Promise((resolve, reject) => { const data = JSON.stringify(body || {}) const req = https.request(url, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(data) } }, res => { let raw = '' res.on('data', chunk => { raw += chunk }) res.on('end', () => { try { resolve(JSON.parse(raw)) } catch (err) { reject(err) } }) }) req.on('error', reject) req.write(data) req.end() }) } let accessTokenCache = null async function getAccessToken() { if (accessTokenCache && accessTokenCache.expiresAt > Date.now() + 60000) return accessTokenCache.token if (!config.wechat.appid || !config.wechat.secret) throw new Error('WECHAT_APPID or WECHAT_SECRET is not configured') const url = 'https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=' + encodeURIComponent(config.wechat.appid) + '&secret=' + encodeURIComponent(config.wechat.secret) const data = await requestJson(url) if (!data.access_token) throw new Error(data.errmsg || 'wechat access_token failed') accessTokenCache = { token: data.access_token, expiresAt: Date.now() + (Number(data.expires_in || 7200) * 1000) } return accessTokenCache.token } async function code2Session(code) { if (config.nodeEnv === 'development' && (!code || code === 'local' || String(code).indexOf('dev_') === 0)) { return { openid: 'dev_openid_' + String(code || 'local').slice(-8) } } if (!config.wechat.appid || !config.wechat.secret) { if (config.nodeEnv === 'development') return { openid: 'dev_openid_' + String(code || 'local').slice(-8) } throw new Error('WECHAT_APPID or WECHAT_SECRET is not configured') } const url = 'https://api.weixin.qq.com/sns/jscode2session?appid=' + encodeURIComponent(config.wechat.appid) + '&secret=' + encodeURIComponent(config.wechat.secret) + '&js_code=' + encodeURIComponent(code) + '&grant_type=authorization_code' const data = await requestJson(url) if (!data.openid) throw new Error(data.errmsg || 'wechat login failed') return data } async function getPhoneNumber(code) { if (!code) throw new Error('phone code required') const token = await getAccessToken() const url = 'https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token=' + encodeURIComponent(token) const data = await postJson(url, { code }) if (data.errcode) throw new Error(data.errmsg || 'get phone number failed') return data.phone_info || null } module.exports = { code2Session, getPhoneNumber }