Created
November 14, 2022 19:37
-
-
Save koreapyj/cbeb8955dbed30f1c260cd8dd54ab6c1 to your computer and use it in GitHub Desktop.
쿠페이 비밀번호 키보드 입력 (Tesseract OCR)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ==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/[email protected]/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