Skip to content
This repository has been archived by the owner on Oct 10, 2023. It is now read-only.

Commit

Permalink
feat: support captcha server
Browse files Browse the repository at this point in the history
  • Loading branch information
shigma committed Jan 16, 2023
1 parent 7b5a7cb commit 2516ec0
Show file tree
Hide file tree
Showing 4 changed files with 91 additions and 13 deletions.
42 changes: 42 additions & 0 deletions captcha.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<!DOCTYPE html>
<html>
<head lang="zh-CN">
<meta charset="UTF-8" />
<meta name="renderer" content="webkit" />
<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />
<title>滑条验证码</title>
</head>
<body>
<div id="cap_iframe" style="width: 230px; height: 220px"></div>
<script type="text/javascript">
!(function () {
const e = document.createElement("script");
e.type = "text/javascript";
e.src = "https://captcha.qq.com/template/TCapIframeApi.js" + location.search;
document.getElementsByTagName("head").item(0).appendChild(e);

function getQueryVariable(variable) {
const query = window.location.search.substring(1);
const vars = query.split('&');
for (let i = 0; i < vars.length; i++) {
const pair = vars[i].split('=');
if (decodeURIComponent(pair[0]) == variable) {
return decodeURIComponent(pair[1]);
}
}
}

e.onload = () => {
capInit(document.getElementById("cap_iframe"), {
callback: (a) => {
fetch(`/gocqhttp/ticket?id=${getQueryVariable("id")}&ticket=${a.ticket}`, {
method: 'POST',
}).finally(() => window.close())
},
showHeader: !1,
});
};
})();
</script>
</body>
</html>
6 changes: 3 additions & 3 deletions client/settings.vue
Original file line number Diff line number Diff line change
Expand Up @@ -35,16 +35,16 @@
</div>
</template>
<template v-else-if="data.status === 'sms-or-qrcode'">
<p>账号已开启设备锁。请选择验证方式 (将在 10 秒后自动选择 2):</p>
<p>账号已开启设备锁。请选择验证方式:</p>
<div class="submit">
<k-button @click="send('gocqhttp/write', sid, '1')">1. 向手机 {{ data.phone }} 发送短信验证码</k-button>
<k-button @click="send('gocqhttp/write', sid, '2')">2. 使用手机登录 QQ 并扫码验证</k-button>
</div>
</template>
<template v-else-if="data.status === 'slider-or-qrcode'">
<p>登录需要滑条验证码。请选择验证方式 (将在 10 秒后自动选择 1):</p>
<p>登录需要滑条验证码。请选择验证方式:</p>
<div class="submit">
<k-button disabled @click="send('gocqhttp/write', sid, '1')">1. 使用浏览器抓取滑条并登录 (暂不支持)</k-button>
<k-button @click="send('gocqhttp/write', sid, '1')">1. 使用浏览器抓取滑条并登录</k-button>
<k-button @click="send('gocqhttp/write', sid, '2')">2. 使用手机登录 QQ 并扫码验证 (需要手机和 Koishi 在同一网络下)</k-button>
</div>
</template>
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"files": [
"lib",
"dist",
"captcha.html",
"install.js",
"template.yml"
],
Expand Down Expand Up @@ -63,7 +64,7 @@
},
"dependencies": {
"@koishijs/utils": "6.4.0",
"go-cqhttp": "^1.1.6",
"go-cqhttp": "^2.1.0",
"strip-ansi": "^6.0.1"
}
}
53 changes: 44 additions & 9 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,12 +95,31 @@ class Launcher extends DataService<Dict<Data>> {
})

ctx.console.addListener('gocqhttp/write', (sid, text) => {
const bot = ctx.bots[sid] as OneBotBot
return new Promise<void>((resolve, reject) => {
bot.process.stdin.write(text + '\n', (error) => {
error ? reject(error) : resolve()
})
})
return this.write(sid, text)
})
})

ctx.router.get('/gocqhttp/captcha', (ctx, next) => {
ctx.type = '.html'
ctx.body = createReadStream(resolve(__dirname, '../captcha.html'))
})

ctx.router.post('/gocqhttp/ticket', (ctx, next) => {
if (!ctx.query.id || !ctx.query.ticket) return ctx.status = 400
const sid = ctx.query.id.toString()
const ticket = ctx.query.ticket.toString()
const bot = this.ctx.bots[sid] as OneBotBot
if (!bot) return ctx.status = 404
ctx.status = 200
return this.write(sid, ticket)
})
}

private async write(sid: string, text: string) {
const bot = this.ctx.bots[sid] as OneBotBot
return new Promise<void>((resolve, reject) => {
bot.process.stdin.write(text + '\n', (error) => {
error ? reject(error) : resolve()
})
})
}
Expand Down Expand Up @@ -156,7 +175,7 @@ class Launcher extends DataService<Dict<Data>> {
data = strip(data.toString()).trim()
if (!data) return
for (const line of data.trim().split('\n')) {
const text = line.slice(23)
const text: string = line.slice(23)
const [type] = text.split(']: ', 1)
if (type in logLevelMap) {
logger[logLevelMap[type]](text.slice(type.length + 3))
Expand All @@ -168,7 +187,7 @@ class Launcher extends DataService<Dict<Data>> {
if (text.includes('アトリは、高性能ですから')) {
resolve()
this.setData(bot, { status: 'success' })
} else if (text.includes('将在10秒后自动选择')) {
} else if (text.includes('请输入(1 - 2)')) {
this.refresh()
} else if (text.includes('账号已开启设备锁') && text.includes('请选择验证方式')) {
this.payload[bot.sid] = { status: 'sms-or-qrcode' }
Expand Down Expand Up @@ -200,12 +219,26 @@ class Launcher extends DataService<Dict<Data>> {
} else if (text.includes('请前往该地址验证')) {
this.setData(bot, {
status: 'slider',
link: text.match(/https:\S+/)[0],
link: text
.match(/https:\S+/)[0]
.replace(/^https:\/\/captcha\.go-cqhttp\.org\/captcha\?id=(.+?)&/, `/gocqhttp/captcha?id=${bot.sid}&`),
})
}
}
})

bot.process.on('error', (error) => {
logger.warn(error)
})

bot.process.stderr.on('data', async (data) => {
data = strip(data.toString()).trim()
if (!data) return
for (const line of data.split('\n')) {
logger.warn(line.trim())
}
})

bot.process.on('exit', () => {
bot.stop()
reject(new Error())
Expand All @@ -225,6 +258,8 @@ class Launcher extends DataService<Dict<Data>> {
}

namespace Launcher {
export const filter = false

export interface Config {
root?: string
logLevel?: number
Expand Down

0 comments on commit 2516ec0

Please sign in to comment.