Skip to content

Instantly share code, notes, and snippets.

@koreapyj
Created November 14, 2022 19:37
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save koreapyj/cbeb8955dbed30f1c260cd8dd54ab6c1 to your computer and use it in GitHub Desktop.
Save koreapyj/cbeb8955dbed30f1c260cd8dd54ab6c1 to your computer and use it in GitHub Desktop.
쿠페이 비밀번호 키보드 입력 (Tesseract OCR)
// ==UserScript==
// @name Coupay Physical Keyboard
// @namespace https://koreapyj.dcmys.kr/
// @version 0.1
// @description Your mother
// @author koreapyj
// @match https://rocketpay.coupang.com/rocketpay/pay/authentication
// @icon https://www.google.com/s2/favicons?sz=64&domain=rocketpay.coupang.com
// @grant none
// ==/UserScript==
(async function() {
'use strict';
document.body.style.display = 'none'
const keyMap = (await (async () => {
const createElement = (parent, tagName, attributes = {}, appendMethod = 'appendChild') => new Promise((resolve, reject) => {
const elem = document.createElement(tagName)
for(const [name, value] of Object.entries(attributes)) {
elem.setAttribute(name, value)
}
if(appendMethod) {
elem.addEventListener('load', () => {resolve(elem)})
elem.addEventListener('error', reject)
parent[appendMethod](elem)
} else {
resolve(elem)
}
})
const getImage = async (src) => new Promise((resolve, reject) => {
const img = new Image
img.src = src
img.addEventListener('load', () => {resolve(img)})
img.addEventListener('reject', reject)
})
await createElement(document.head, 'script', {
src: 'https://unpkg.com/tesseract.js@2.1.0/dist/tesseract.min.js',
type: 'text/javascript',
})
const rects = Array.from(document.querySelectorAll('.rocketpay-keypad-key > span')).map(elem=>{
const style = getComputedStyle(elem)
const [left, top] = style['background-position'].split(' ').map(x=>~~x.replace(/[^\d]/g,''))
const [width, height] = [style.width, style.height].map(x=>parseInt(x))
return {left, top, width, height}
})
const url = getComputedStyle(document.querySelector('.rocketpay-keypad-key > span'))['background-image'].match(/^url\((['"])(.*)\1/)[2]
const image = await getImage(url)
const canvas = await createElement(null, 'canvas', {width: image.width, height: image.height}, null)
const imageDataUrl = (() => {
const ctx = canvas.getContext('2d')
ctx.fillStyle = 'black'
ctx.fillRect(0, 0, canvas.width, canvas.height)
ctx.drawImage(image, 0, 0)
return canvas.toDataURL('image/png')
})()
const values = await Promise.all((() => {
const promises = []
for (const rectangle of rects) {
promises.push((async() => {
const worker = Tesseract.createWorker()
await worker.load()
await worker.loadLanguage('eng');
await worker.initialize('eng');
await worker.setParameters({
tessedit_char_whitelist: '0123456789',
});
const { data: { text } } = await worker.recognize(imageDataUrl, { rectangle });
await worker.terminate();
return ~~text
})())
}
return promises
})())
return values
})()).reduce((obj, value, key) => {
obj[value] = document.querySelector(`.rocketpay-keypad-position-${key}`).parentNode
return obj
}, {})
keyMap['Backspace'] = document.querySelector('.rocketpay-keypad-edit')
for(let i=0;i<10;i++) {
if(!keyMap[i]) throw new Error(`Failed to recognize key map. Key ${i} is missing`)
}
document.addEventListener('keydown', async (e) => {
/* PIN 키보드 */
if(keyMap) {
const buttons = keyMap
const {key} = e
buttons[key].dispatchEvent(new MouseEvent('click'))
}
})
document.body.style.display = ''
document.body.focus()
})()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment