|
@@ -8,16 +8,22 @@ const { parse, compileTemplate } = require('@vue/compiler-sfc')
|
|
|
const read = p => readFileSync(new URL(p, import.meta.url), 'utf8')
|
|
const read = p => readFileSync(new URL(p, import.meta.url), 'utf8')
|
|
|
const strip = s => s.replace(/^import[^\n]+\n/gm, '').replace(/^export /gm, '')
|
|
const strip = s => s.replace(/^import[^\n]+\n/gm, '').replace(/^export /gm, '')
|
|
|
|
|
|
|
|
|
|
+const launchState = 'a'.repeat(32)
|
|
|
|
|
+const launchUrl = `https://w.shanxiachem.com/api/public/wechat-notices/oauth/launch?state=${launchState}`
|
|
|
|
|
+
|
|
|
function api(data, statusCode = 200, code = 200) {
|
|
function api(data, statusCode = 200, code = 200) {
|
|
|
const calls = []
|
|
const calls = []
|
|
|
const source = strip(read('../api/wechat-notices.js'))
|
|
const source = strip(read('../api/wechat-notices.js'))
|
|
|
- const fns = new Function('request', 'parseResponseJson', `${source}; return { startWechatBinding, fetchWechatBindingSession, confirmWechatBinding, isWechatAuthorizeUrl }`)(
|
|
|
|
|
- async options => { calls.push(options); return { statusCode, data: { code, data, message: '请求失败' } } }, response => response.data)
|
|
|
|
|
|
|
+ const fns = new Function('request', 'parseResponseJson', 'resolveWebOrigin', 'resolveApiBase', `${source}; return { startWechatBinding, fetchWechatBindingSession, confirmWechatBinding, isWechatAuthorizeUrl }`)(
|
|
|
|
|
+ async options => { calls.push(options); return { statusCode, data: { code, data, message: '请求失败' } } },
|
|
|
|
|
+ response => response.data,
|
|
|
|
|
+ () => 'https://w.shanxiachem.com',
|
|
|
|
|
+ () => 'https://w.shanxiachem.com/api')
|
|
|
return { ...fns, calls }
|
|
return { ...fns, calls }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
test('binding API uses owner-authenticated endpoints and only returns necessary fields', async () => {
|
|
test('binding API uses owner-authenticated endpoints and only returns necessary fields', async () => {
|
|
|
- const start = api({ sessionId: 'a'.repeat(32), authorizeUrl: 'https://open.weixin.qq.com/connect/oauth2/authorize?state=state#wechat_redirect', openid: 'private' })
|
|
|
|
|
|
|
+ const start = api({ sessionId: 'a'.repeat(32), authorizeUrl: launchUrl, openid: 'private' })
|
|
|
assert.equal((await start.startWechatBinding()).openid, undefined)
|
|
assert.equal((await start.startWechatBinding()).openid, undefined)
|
|
|
assert.equal(start.calls[0].method, 'POST')
|
|
assert.equal(start.calls[0].method, 'POST')
|
|
|
assert.deepEqual(start.calls[0].data, { mode: 'mobile' })
|
|
assert.deepEqual(start.calls[0].data, { mode: 'mobile' })
|
|
@@ -32,7 +38,13 @@ test('binding API uses owner-authenticated endpoints and only returns necessary
|
|
|
|
|
|
|
|
test('binding API rejects foreign URLs, failed and malformed results', async () => {
|
|
test('binding API rejects foreign URLs, failed and malformed results', async () => {
|
|
|
const fns = api({})
|
|
const fns = api({})
|
|
|
- for (const url of ['javascript:alert(1)', 'http://open.weixin.qq.com/connect/oauth2/authorize?state=x', 'https://open.weixin.qq.com.evil.test/connect/oauth2/authorize?state=x']) {
|
|
|
|
|
|
|
+ for (const url of [
|
|
|
|
|
+ 'javascript:alert(1)',
|
|
|
|
|
+ 'http://open.weixin.qq.com/connect/oauth2/authorize?state=x',
|
|
|
|
|
+ 'https://open.weixin.qq.com/connect/oauth2/authorize?state=' + launchState,
|
|
|
|
|
+ 'https://evil.test/api/public/wechat-notices/oauth/launch?state=' + launchState,
|
|
|
|
|
+ launchUrl + '#wechat_redirect'
|
|
|
|
|
+ ]) {
|
|
|
assert.equal(fns.isWechatAuthorizeUrl(url), false)
|
|
assert.equal(fns.isWechatAuthorizeUrl(url), false)
|
|
|
await assert.rejects(api({ sessionId: 'x'.repeat(32), authorizeUrl: url }).startWechatBinding())
|
|
await assert.rejects(api({ sessionId: 'x'.repeat(32), authorizeUrl: url }).startWechatBinding())
|
|
|
}
|
|
}
|
|
@@ -53,7 +65,7 @@ test('authorization page mounts approved URL after ready and unregisters its cha
|
|
|
const page = new Function(...Object.keys(deps), `${body}; return { src, errorText, onError }`)(...Object.values(deps))
|
|
const page = new Function(...Object.keys(deps), `${body}; return { src, errorText, onError }`)(...Object.values(deps))
|
|
|
hooks.load({ url: 'https://evil.test' })
|
|
hooks.load({ url: 'https://evil.test' })
|
|
|
assert.equal(page.src.value, '')
|
|
assert.equal(page.src.value, '')
|
|
|
- const url = 'https://open.weixin.qq.com/connect/oauth2/authorize?state=xyz'
|
|
|
|
|
|
|
+ const url = launchUrl
|
|
|
handlers.wechatBindingAuthorize({ authorizeUrl: url })
|
|
handlers.wechatBindingAuthorize({ authorizeUrl: url })
|
|
|
assert.equal(page.src.value, '')
|
|
assert.equal(page.src.value, '')
|
|
|
hooks.ready()
|
|
hooks.ready()
|