puppet-supports icon indicating copy to clipboard operation
puppet-supports copied to clipboard

监听与输入企业微信登录验证码

Open hcfw007 opened this issue 2 years ago • 23 comments

监听与输入企业微信登录验证码

近期,企业微信在一些账号首次登录设备时,会要求输入验证码。形式如下:

image

为了尽快适配此功能,我们在 @juzi/wechaty 包中率先实现了验证码事件和输入验证码的方法。我们也会接下来推动这一方法在社区版实现。需要注意的是,我们目前只能保证 node 版 wechaty 的使用体验,暂时没有多余的人手推动其他版本的迭代,为了更好的使用 token ,请尽量使用 node 版本的 wechaty。 ( @juzi/wechaty 只提供了 node 版本)

依赖版本

@juzi/[email protected]

@juzi/[email protected]

@juzi/[email protected]

类型定义

export enum VerifyCodeStatus {
  UNKNOWN = 0,
  WAITING = 1, // 待输入
  EXPIRED = 2, // 过期,尚未实装,目前应该根据接口返回抛错来判断是否过期
}

export enum VerifyCodeScene {
  UNKNOWN = 0,
  LOGIN = 1, // 登录验证码
}

type WechatyEventListenerVerifyCode = (
  id: string, // 验证码 id ,在登录场景下,与登录链接中的 key 对应
  message: string, // 验证码附带文字消息,目前固定为 请输入企业微信手机端展示的验证码,以继续登录
  scene: PUPPET.types.VerifyCodeScene, // 验证码场景,目前只有 登录
  status: PUPPET.types.VerifyCodeStatus // 验证码状态,目前只实现了 待输入
 ) => void | Promise<void>
 
 // 监听事件
bot.on('verify-code', async (id: string, message: string, scene: types.VerifyCodeScene, status: types.VerifyCodeStatus) => {
  // code here
})

相关方法

async enterVerifyCode (
  id: string,
  code: string,
): Promise<void> // 输入验证码
  
async cancelVerifyCode (
  id: string,
): Promise<void> // 取消验证码 (会导致二维码刷新)

async refreshQrCode (): Promise<void> // 强制刷新二维码

使用说明

在验证码事件 verify-code 推送的过程中,扫码事件 scan 也会继续推送 ( status 为 4 Confirmed )。bot 开发者应该关注 verify-code 事件的 id 字段,并将其与 scan 事件的 qrcode 字段进行比较。qrcode 字段是形式如 https://wx.work.weixin.qq.com/cgi-bin/crtx_auth?key=${qrcodeKey}&wx=1 的字符串,我们应该比较其中的 qrcodeKeyverify-code 事件的 id,如果两个不相同,说明出了新的二维码,需要重新扫码。

示例

输入验证码

const store = {}

bot.on('scan', (qrcode: string, status: types.ScanStatus) => {
  if (status === types.ScanStatus.Waiting) {
    // 新二维码
    store.qrcodeKey= getQrcodeKey(qrcode)
  }
}).on('verify-code', async (id: string, message: string, scene: types.VerifyCodeScene, status: types.VerifyCodeStatus) => {
  if (status === types.VerifyCodeStatus.WAITING && scene === types.VerifyCodeScene.LOGIN && id === store.qrcodeKey) {
    const verifyCode = await getVerifyCode() // 通过一些途径输入验证码
    try {
      await bot.enterVerifyCode(id, verifyCode) // 如果没抛错,则说明输入成功,会推送登录事件
      return
    } catch (e) {
      console.log(e.message)
      // 如果抛错,请根据 message 处理,目前发现可以输错3次,超过3次错误需要重新扫码。
      // 错误关键词: 验证码错误输入错误,请重新输入
      // 错误关键词:验证码错误次数超过阈值,请重新扫码'
      // 目前不会推送 EXPIRED 事件,需要根据错误内容判断
    }
  }
})

刷新验证码

await bot.cancelVerifyCode(store.qrcodeKey) // 根据 key 取消验证码 (需要重新扫码,不是更换验证码),但必须要在等待验证码状态才可以使用。

await bot.refreshQrCode() // 刷新二维码,任何情况都可使用

其他

请注意,相关文档可能会变化,但此 Issue 不一定能即时更新。请关注相关飞书文档,后期在我们的 token 自助系统上线后也会有 @juzi/wechaty 包的文档。

可运行实例

请使用这个 codespace

示例代码

请查看这个 repo workpro-getting-started.

hcfw007 avatar Aug 31 '23 10:08 hcfw007

@hcfw007 请问,调用 bot.enterVerifyCode(id, verifyCode) 时出现 this.puppet.enterVerifyCode is not a function 报错是为何引起的?

以下是我调用时的部分代码

export async function submitLoginVerifyCode(verifyCode: string) {
  log.info("提交登录验证码 ->", `qrcodeKey: ${loginStore.qrcodeKey}; verifyCode: ${verifyCode}`);
  await getBot().enterVerifyCode(loginStore.qrcodeKey, verifyCode);
}

输出日志为

11:02:05 INFO 提交登录验证码 -> qrcodeKey: B3DB5551B3DAD4A096485981A62F3BDD; verifyCode: 459209
error -> TypeError: this.puppet.enterVerifyCode is not a function
    at WechatyImpl.enterVerifyCode (D:\Projects\xxx-puppet\node_modules\@juzi\wechaty\dist\cjs\src\wechaty\wechaty-base.js:255:28)
    at D:\Projects\xxx-puppet\dist\src\bot\bot.js:80:24
    at Generator.next (<anonymous>)
    at D:\Projects\xxx-puppet\dist\src\bot\bot.js:8:71
    at new Promise (<anonymous>)
    at __awaiter (D:\Projects\xxx-puppet\dist\src\bot\bot.js:4:12)
    at submitLoginVerifyCode (D:\Projects\xxx-puppet\dist\src\bot\bot.js:78:12)
    at D:\Projects\xxx-puppet\dist\src\bot\botProcess.js:60:51
    at Generator.next (<anonymous>)
    at D:\Projects\xxx-puppet\dist\src\bot\botProcess.js:8:71

依赖版本

"@juzi/wechaty": "^1.0.65",
"@juzi/wechaty-puppet": "^1.0.61",
"@juzi/wechaty-puppet-service": "^1.0.69",

KroMiose avatar Sep 01 '23 03:09 KroMiose

建议你们最好能提供一个最小的能运行的最新版本的example,比提供一些没有context的代码片段强多了

LLSean avatar Sep 01 '23 06:09 LLSean

@hcfw007 请问,调用 bot.enterVerifyCode(id, verifyCode) 时出现 this.puppet.enterVerifyCode is not a function 报错是为何引起的?

以下是我调用时的部分代码

export async function submitLoginVerifyCode(verifyCode: string) {
  log.info("提交登录验证码 ->", `qrcodeKey: ${loginStore.qrcodeKey}; verifyCode: ${verifyCode}`);
  await getBot().enterVerifyCode(loginStore.qrcodeKey, verifyCode);
}

输出日志为

11:02:05 INFO 提交登录验证码 -> qrcodeKey: B3DB5551B3DAD4A096485981A62F3BDD; verifyCode: 459209
error -> TypeError: this.puppet.enterVerifyCode is not a function
    at WechatyImpl.enterVerifyCode (D:\Projects\xxx-puppet\node_modules\@juzi\wechaty\dist\cjs\src\wechaty\wechaty-base.js:255:28)
    at D:\Projects\xxx-puppet\dist\src\bot\bot.js:80:24
    at Generator.next (<anonymous>)
    at D:\Projects\xxx-puppet\dist\src\bot\bot.js:8:71
    at new Promise (<anonymous>)
    at __awaiter (D:\Projects\xxx-puppet\dist\src\bot\bot.js:4:12)
    at submitLoginVerifyCode (D:\Projects\xxx-puppet\dist\src\bot\bot.js:78:12)
    at D:\Projects\xxx-puppet\dist\src\bot\botProcess.js:60:51
    at Generator.next (<anonymous>)
    at D:\Projects\xxx-puppet\dist\src\bot\botProcess.js:8:71

依赖版本

"@juzi/wechaty": "^1.0.65",
"@juzi/wechaty-puppet": "^1.0.61",
"@juzi/wechaty-puppet-service": "^1.0.69",

我觉得最大的可能是bot build的时候没有引用@juzi/wechaty-puppet-service

hcfw007 avatar Sep 01 '23 06:09 hcfw007

@KroMiose package.json里把之前旧的依赖删除,引入@hcfw007提供的就可以

LLSean avatar Sep 01 '23 07:09 LLSean

感谢解答!问题已解决,引用的依赖都是@juzi/wechaty没错,在 WechatyBuilder.build 参数中传入的 puppet 改为 puppet: "@juzi/wechaty-puppet-service" 即可

KroMiose avatar Sep 01 '23 07:09 KroMiose

嗯,你把旧的依赖删了这里会报错的,比较容易找到问题

LLSean avatar Sep 01 '23 07:09 LLSean

@hcfw007 请问,调用 bot.enterVerifyCode(id, verifyCode) 时出现 this.puppet.enterVerifyCode is not a function 报错是为何引起的? 以下是我调用时的部分代码

export async function submitLoginVerifyCode(verifyCode: string) {
  log.info("提交登录验证码 ->", `qrcodeKey: ${loginStore.qrcodeKey}; verifyCode: ${verifyCode}`);
  await getBot().enterVerifyCode(loginStore.qrcodeKey, verifyCode);
}

输出日志为

11:02:05 INFO 提交登录验证码 -> qrcodeKey: B3DB5551B3DAD4A096485981A62F3BDD; verifyCode: 459209
error -> TypeError: this.puppet.enterVerifyCode is not a function
    at WechatyImpl.enterVerifyCode (D:\Projects\xxx-puppet\node_modules\@juzi\wechaty\dist\cjs\src\wechaty\wechaty-base.js:255:28)
    at D:\Projects\xxx-puppet\dist\src\bot\bot.js:80:24
    at Generator.next (<anonymous>)
    at D:\Projects\xxx-puppet\dist\src\bot\bot.js:8:71
    at new Promise (<anonymous>)
    at __awaiter (D:\Projects\xxx-puppet\dist\src\bot\bot.js:4:12)
    at submitLoginVerifyCode (D:\Projects\xxx-puppet\dist\src\bot\bot.js:78:12)
    at D:\Projects\xxx-puppet\dist\src\bot\botProcess.js:60:51
    at Generator.next (<anonymous>)
    at D:\Projects\xxx-puppet\dist\src\bot\botProcess.js:8:71

依赖版本

"@juzi/wechaty": "^1.0.65",
"@juzi/wechaty-puppet": "^1.0.61",
"@juzi/wechaty-puppet-service": "^1.0.69",

我觉得最大的可能是bot build的时候没有引用@juzi/wechaty-puppet-service

image 你们这个依赖的版本需要替换以前package.json的哪几个依赖吗?我的verify-code监听事件不奏效呢 目前我安装的依赖 image

charleyCC avatar Sep 20 '23 03:09 charleyCC

不生效的最大可能是你只是安装了依赖,但在代码中创建实例时仍然使用了旧的依赖。

hcfw007 avatar Sep 20 '23 03:09 hcfw007

        let verifyCode = fs.readFileSync(conf.wxVerifyCodeFile).toString();
        console.log(`bot.config id:${id}, verifyCode: ${verifyCode}`)
        try {
            await bot.enterVerifyCode(id, verifyCode) // 如果没抛错,则说明输入成功,会推送登录事件
            return
        } catch (e) {
            console.log(`enterVerifyCode error : ${JSON.stringify(e)}`)
        }

错误信息如下,是什么原因呢? {"code":13,"details":"Invalid verify code!","metadata":{"content-type":["application/grpc+proto"],"date":["Wed, 20 Sep 2023 09:02:10 GMT"],"authorization":["Wechaty undefined"]}}

xronghui avatar Sep 20 '23 09:09 xronghui

        let verifyCode = fs.readFileSync(conf.wxVerifyCodeFile).toString();
        console.log(`bot.config id:${id}, verifyCode: ${verifyCode}`)
        try {
            await bot.enterVerifyCode(id, verifyCode) // 如果没抛错,则说明输入成功,会推送登录事件
            return
        } catch (e) {
            console.log(`enterVerifyCode error : ${JSON.stringify(e)}`)
        }

错误信息如下,是什么原因呢? {"code":13,"details":"Invalid verify code!","metadata":{"content-type":["application/grpc+proto"],"date":["Wed, 20 Sep 2023 09:02:10 GMT"],"authorization":["Wechaty undefined"]}}

就是错误码有误。请注意是否包含了空格、换行、不可显字符等特殊字符。

hcfw007 avatar Sep 27 '23 10:09 hcfw007

        let verifyCode = fs.readFileSync(conf.wxVerifyCodeFile).toString();
        console.log(`bot.config id:${id}, verifyCode: ${verifyCode}`)
        try {
            await bot.enterVerifyCode(id, verifyCode) // 如果没抛错,则说明输入成功,会推送登录事件
            return
        } catch (e) {
            console.log(`enterVerifyCode error : ${JSON.stringify(e)}`)
        }

错误信息如下,是什么原因呢? {"code":13,"details":"Invalid verify code!","metadata":{"content-type":["application/grpc+proto"],"date":["Wed, 20 Sep 2023 09:02:10 GMT"],"authorization":["Wechaty undefined"]}}

相同的问题解决了,验证码要字符串类型不是数字,同时使用text.replace(/\s+/g, '')去除空格和字符串,已经登录,有问题可以联系我v:jitasanshao

myllq avatar Dec 14 '23 04:12 myllq

启动报错 08:59:53 INFO PuppetSkeleton start() 08:59:53 INFO PuppetService start() instanciating GrpcManager ... 08:59:53 INFO PuppetService start() instanciating GrpcManager ... done 08:59:53 INFO PuppetService start() setting up bridge grpc event stream ... 08:59:53 INFO PuppetService start() setting up bridge grpc event stream ... done 08:59:53 INFO PuppetService start() starting grpc manager... 08:59:53 WARN last event was 1708995593.491 seconds ago, will not request event cache 08:59:53 WARN GrpcManager initClient() TLS: disabled (INSECURE) 08:59:53 INFO GrpcManager startStream() connecting event stream with account undefined and seq undefined /home/test2/workpro-getting-started-latest-features/node_modules/@grpc/grpc-js/src/subchannel-address.ts:40 return 'port' in address; ^ TypeError: Cannot use 'in' operator to search for 'port' in undefined at isTcpSubchannelAddress (/home/test2/workpro-getting-started-latest-features/node_modules/@grpc/grpc-js/src/subchannel-address.ts:40:16) at interleaveAddressFamilies (/home/test2/workpro-getting-started-latest-features/node_modules/@grpc/grpc-js/src/load-balancer-pick-first.ts:145:27) at PickFirstLoadBalancer.updateAddressList (/home/test2/workpro-getting-started-latest-features/node_modules/@grpc/grpc-js/src/load-balancer-pick-first.ts:520:25) at ChildLoadBalancerHandler.updateAddressList (/home/test2/workpro-getting-started-latest-features/node_modules/@grpc/grpc-js/src/load-balancer-child-handler.ts:137:19) at onSuccessfulResolution (/home/test2/workpro-getting-started-latest-features/node_modules/@grpc/grpc-js/src/resolving-load-balancer.ts:298:34) at processTicksAndRejections (node:internal/process/task_queues:86:22)

15638192475 avatar Feb 27 '24 01:02 15638192475

TypeError: Cannot use 'in' operator to search for 'port' in undefined

@15638192475 参考这个issue: https://github.com/wechaty/puppet-supports/issues/364#issuecomment-1952270004

su-chang avatar Feb 28 '24 07:02 su-chang

我写了一个md汇总了会遇到的问题及解决方案,包括怎么实现输入验证码 @hcfw007 Wework Bot问题汇总,有帮助的话点个star

ps:我这个能算贡献者吗

petrichor112321 avatar Apr 02 '24 09:04 petrichor112321

ps:我这个能算贡献者吗

@petrichor112321 额,这个不太行。

su-chang avatar Apr 02 '24 10:04 su-chang

无法监听到verify-code事件 是什么原因?

Lyq0055 avatar May 16 '24 03:05 Lyq0055

无法监听到verify-code事件 是什么原因?

检查下依赖版本?

hcfw007 avatar May 16 '24 08:05 hcfw007

@hcfw007 store.qrcodeKey= getQrcodeKey(qrcode)和 const verifyCode = await getVerifyCode()的getQrcodeKey、getVerifyCode是怎么来的?是后端写的还是某一个依赖里面自带的?

GiockL avatar Aug 15 '24 07:08 GiockL

为什么监听不到verify-code这个事件,扫码登录后,监听验证码事件没有响应

yunfeng13 avatar Aug 23 '24 06:08 yunfeng13

@hcfw007 store.qrcodeKey= getQrcodeKey(qrcode)和 const verifyCode = await getVerifyCode()的getQrcodeKey、getVerifyCode是怎么来的?是后端写的还是某一个依赖里面自带的?

自行编码获取。

hcfw007 avatar Aug 24 '24 15:08 hcfw007

为什么监听不到verify-code这个事件,扫码登录后,监听验证码事件没有响应

请确保使用@juzi的依赖包

hcfw007 avatar Aug 24 '24 15:08 hcfw007