SCNU SSO 验证码自动填充

基于 tensorflow.js SCNU SSO 验证码自动填充, 0.89~0.93 准确率

  1. // ==UserScript==
  2. // @name SCNU SSO auto captcha filler
  3. // @name:zh-CN SCNU SSO 验证码自动填充
  4. // @namespace https://github.com/fengkx/
  5. // @match https://sso.scnu.edu.cn/AccountService/openapi/login.html*
  6. // @match https://sso.scnu.edu.cn/AccountService/user/login.html*
  7. // @match https://sso.scnu.edu.cn/AccountService/user/index.html*
  8. // @grant none
  9. // @version 2.0
  10. // @author fengkx
  11. // @description scnu sso captcha auto filler using tensorflow.js 0.89~0.93 accuracy
  12. // @description:zh-CN 基于 tensorflow.js SCNU SSO 验证码自动填充, 0.89~0.93 准确率
  13. // @supportURL https://github.com/fengkx/scnu-sso-captcha
  14. // @run-at document-end
  15. // @require https://cdn.jsdelivr.net/npm/@tensorflow/tfjs@2.7.0/dist/tf.min.js
  16. // @require https://cdn.jsdelivr.net/npm/opencv.js@1.2.1/opencv.min.js
  17. // ==/UserScript==
  18.  
  19. const WIDTH = 100
  20. const IDICT = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'
  21. const HEIGHT = 50
  22.  
  23. const $input = document.getElementById('rancode')
  24. const img =
  25. document.getElementById('codeimg') || document.getElementById('code')
  26.  
  27. const $canvas = document.createElement('canvas')
  28. $canvas.addEventListener('click', window.reloadcode)
  29. $canvas.width = WIDTH
  30. $canvas.height = HEIGHT
  31. const isUseLite = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini|Mobile|mobile|CriOS/.test(navigator.userAgent)
  32. const modelDir = isUseLite ? 'js-model-lite' : 'js-model'
  33. const modelVersion = 'v2'
  34. const modelKey = `${modelVersion}/${modelDir}`
  35. const MODEL_URL = `https://cdn.jsdelivr.net/gh/fengkx/scnu-sso-captcha@master/web-model/${modelKey}/model.json`;
  36. console.debug(MODEL_URL)
  37. console.log(
  38. `${'\n'} %c SCNU SSO auto captcha filler v2.0 %c https://github.com/fengkx/scnu-sso-captcha ${'\n'}${'\n'}`,
  39. 'color: #000; background: #fffcc8; padding:5px 0;',
  40. 'background: #fadfa3; padding:5px 0;'
  41. )
  42. let model = null;
  43. async function main() {
  44. const $img = img.cloneNode()
  45. $img.width = WIDTH
  46. $img.height = HEIGHT
  47.  
  48. const ctx = $canvas.getContext('2d')
  49. $canvas.classList.add('input-addon')
  50. $canvas.style.right = '100px'
  51. $input.parentElement.appendChild($canvas)
  52. ctx.drawImage($img, 0, 0)
  53. const imageData = ctx.getImageData(0, 0, WIDTH, HEIGHT)
  54. const mat = cv.matFromImageData(imageData)
  55. let dst = new cv.Mat()
  56. let src = mat
  57. cv.cvtColor(src, src, cv.COLOR_BGR2GRAY, 0)
  58. cv.adaptiveThreshold(
  59. src,
  60. src,
  61. 255,
  62. cv.ADAPTIVE_THRESH_GAUSSIAN_C,
  63. cv.THRESH_BINARY_INV,
  64. 15,
  65. 15
  66. )
  67. cv.medianBlur(src, dst, 3)
  68. cv.imshow($canvas, dst)
  69. x = tf.browser.fromPixels($canvas)
  70. x = x.div(255)
  71. x = x.max(2).expandDims(2)
  72. console.debug(x.shape)
  73. x = await x.array()
  74. const old = Date.now()
  75. if(!model) {
  76. try {
  77. model = await tf.loadGraphModel('indexeddb://' + modelKey)
  78. } catch (e) {
  79. model = await tf.loadGraphModel(MODEL_URL)
  80. const saveResults = await model.save('indexeddb://' + modelKey)
  81. }
  82. }
  83. let p = model.predict(tf.tensor([x]))
  84. const used = (Date.now() - old) / 1000
  85. console.debug(used)
  86. p = await p.array()
  87. p = tf.tensor(p[0])
  88. p = p.argMax(1)
  89. p = await p.array()
  90. p = p.map((idx) => IDICT[idx]).join('')
  91. console.log(p)
  92. $input.value = p
  93. }
  94. document.addEventListener('readystatechange', (event) => {
  95. if (event.target.readyState === 'complete') {
  96. main()
  97. }
  98. });
  99.  
  100. img.addEventListener('load', main)