Skip to content

Commit

Permalink
keytap3-gui : new stable version of the GUI
Browse files Browse the repository at this point in the history
  • Loading branch information
ggerganov committed May 2, 2022
1 parent df87502 commit 7706c48
Show file tree
Hide file tree
Showing 7 changed files with 401 additions and 94 deletions.
14 changes: 14 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,20 @@ if (EMSCRIPTEN)

configure_file(${CMAKE_SOURCE_DIR}/index-${TARGET}-tmpl.html ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/index.html @ONLY)
configure_file(${CMAKE_SOURCE_DIR}/style.css ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/style.css @ONLY)

# keytap3-gui
set(TARGET keytap3-gui)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/${TARGET})

set_target_properties(${TARGET} PROPERTIES LINK_FLAGS " \
-s TOTAL_MEMORY=536870912 \
-s FORCE_FILESYSTEM=1 \
-s LZ4=1 \
--preload-file ${PROJECT_SOURCE_DIR}/data/ggwords-6-gram.dat.binary@/data/ \
")

configure_file(${CMAKE_SOURCE_DIR}/index-${TARGET}-tmpl.html ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/index.html @ONLY)
configure_file(${CMAKE_SOURCE_DIR}/style.css ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/style.css @ONLY)
endif()

if (NOT EMSCRIPTEN)
Expand Down
20 changes: 18 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ A more detailed description of the tool is available here: [Keytap2 discussion](
[CTF: can you guess the text being typed?](https://ggerganov.github.io/keytap-challenge/)

[Try it online:](https://keytap2.ggerganov.com)

<a href="https://keytap2.ggerganov.com" target="_blank"><img src="https://i.imgur.com/nPlLEDN.jpg" style="display: inline-block; overflow: hidden; width: 99%;"></img></a>

### Keytap3
Expand All @@ -39,6 +39,8 @@ automated and does not require any manual intervation during the text recovery p

[Video: short demo of using Keytap3](https://youtu.be/5aphvxpSt3o)

[GUI for Keytap3](https://keytap3.ggerganov.com)

[Check if your keyboard is vulnerable to Keytap:](https://keytap3.ggerganov.com)

<a href="https://keytap3.ggerganov.com" target="_blank"><img src="https://user-images.githubusercontent.com/1991296/166096331-ab26f7f8-08e0-48d6-abd7-57017ebf1866.JPEG" style="display: inline-block; overflow: hidden; width: 99%;"></img></a>
Expand Down Expand Up @@ -99,6 +101,7 @@ Short summary of the available tools. If the status of the tool is not **stable*
| **keytap-gui** | gui | **stable** |
| **keytap2-gui** | gui | **stable** |
| **keytap3** | text | **stable** |
| **keytap3-gui** | gui | **stable** |
| - | *extra* | - |
| **guess-qp** | text | experiment |
| **guess-qp2** | text | experiment |
Expand All @@ -107,7 +110,6 @@ Short summary of the available tools. If the status of the tool is not **stable*
| **subreak** | text | experiment |
| **key-average-gui** | gui | experiment |
| **keytap2** | text | experiment |
| **keytap3-gui** | gui | experiment |

## Tool details

Expand Down Expand Up @@ -157,6 +159,8 @@ Short summary of the available tools. If the status of the tool is not **stable*

./keytap-gui input0.kbd [input1.kbd] [input2.kbd] ... [-cN] [-CN]

Online demo: https://keytap.ggerganov.com

---

* **keytap2-gui** record.kbd n-gram-dir [-pN] [-cN] [-CN]
Expand All @@ -165,6 +169,8 @@ Short summary of the available tools. If the status of the tool is not **stable*

./keytap2-gui record.kbd ../data

Online demo: https://keytap2.ggerganov.com

---

* **keytap3**
Expand All @@ -177,6 +183,16 @@ Short summary of the available tools. If the status of the tool is not **stable*

---

* **keytap3-gui**

GUI version of the **keytap3** tool.

./keytap3-gui input.kbd ../data [-cN] [-CN] [-pF] [-tF] [-FN] [-fN]

Online demo: https://keytap3-gui.ggerganov.com

---

* **view-full-gui**

Visualize waveforms recorded with the **record-full** tool. Can also playback the audio data.
Expand Down
2 changes: 1 addition & 1 deletion index-keytap2-gui-tmpl.html
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,6 @@ <h2>Keytap2 - acoustic keyboard eavesdropping based on language n-gram frequenci

</script>

<script async type="text/javascript" src="keytap2-gui.js"></script>
<script async type="text/javascript" src="@TARGET@.js"></script>
</body>
</html>
253 changes: 253 additions & 0 deletions index-keytap3-gui-tmpl.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,253 @@
<!doctype html>
<html lang="en-us">
<head>
<meta charset="utf-8">
<title>Keytap3</title>

<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no"/>

<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="Keytap3" />
<meta name="twitter:description" content="Acoustic keyboard eavesdropping based on language n-gram frequencies" />
<meta name="twitter:image" content="https://keytap3.ggerganov.com/keytap3.png" />

<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png">
<link rel="manifest" href="/site.webmanifest">

<meta name="msapplication-TileColor" content="#ffffff">
<meta name="msapplication-TileImage" content="/ms-icon-144x144.png">
<meta name="theme-color" content="#ffffff">

<link rel="stylesheet" href="style.css">
</head>
<body>
<div id="main-controls">
<div id="description">
<h2>Keytap3 - acoustic keyboard eavesdropping</h2>

<span class="text-body">
This is a GUI for <a class="nav-link2" href="https://keytap3.ggerganov.com">Keytap3</a><br>

<br>

This tool runs entirely in your browser. No data is sent or stored to a server.

<br><br>

Press the "Init" button to start:

<br><br>
</span>

<div align="center">
<button onClick="doInit()" id="butInit" style="width:60px;height:30px;" disabled>Init</button>
<br><br>
<div class="nav-link2" id="download-info">Downloading WASM module and n-gram stats. Please wait ...</div>
</div>
</div>
<canvas class="emscripten" id="canvas" oncontextmenu="event.preventDefault()" hidden></canvas>
</div>

<div id="footer" class="cell-version">
<span>
Build time: <span class="nav-link">@GIT_DATE@</span> |
Commit hash: <a class="nav-link" href="https://github.com/ggerganov/kbd-audio/commit/@GIT_SHA1@">@GIT_SHA1@</a> |
Commit subject: <span class="nav-link">@GIT_COMMIT_SUBJECT@</span> |
</span>
</div>
<div id="footer2" class="cell-about">
<a class="nav-link" href="https://github.com/ggerganov/kbd-audio"><span class="d-none d-sm-inline">View on GitHub </span>
<svg version="1.1" width="16" height="16" viewBox="0 0 16 16" class="octicon octicon-mark-github" aria-hidden="true"><path fill-rule="evenodd" d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0 0 16 8c0-4.42-3.58-8-8-8z"></path></svg>
</a>
</div>

<script type='text/javascript'>
window.mobilecheck = function() {
var check = false;
(function(a){if(/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test(a)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(a.substr(0,4))) check = true;})(navigator.userAgent||navigator.vendor||window.opera);
return check;
};

var isMobile = mobilecheck();
var isInitialized = false;

var screenX = -1;
var screenY = -1;

var oldOutputId = 0;

window.setInterval(function(){
if (isMobile) {
document.getElementById("footer").innerHTML = '';
document.getElementById("footer2").innerHTML = '';
}
if (isInitialized == false) return;
var w = window,
d = document,
e = d.documentElement,
g = d.getElementsByTagName('body')[0],
x = w.innerWidth || e.clientWidth || g.clientWidth,
y = w.innerHeight|| e.clientHeight|| g.clientHeight;
Module._set_window_size(0.99*x, y - 1.40*document.getElementById('footer').clientHeight);
}, 500);

function checkLoop() {
var outputId = Module._get_output_id();
if (outputId != oldOutputId) {
offerFileAsDownload('record.kbd', 'mime/type');
oldOutputId = outputId;
}

setTimeout(checkLoop, 100);
}

function onkeydown(event) {
if (event.keyCode >= 112 && event.keyCode <= 123) {
event.stopImmediatePropagation();
}
}

function init() {
document.getElementById("butInit").disabled = false;
document.getElementById("download-info").innerHTML = "WASM module initialized!";

window.addEventListener('keydown', onkeydown, true);

document.getElementById("canvas").addEventListener("dragover", (event) => {
event.preventDefault();
});

document.getElementById("canvas").addEventListener("drop", (event) => {
event.preventDefault();

dropHandler(event);
});

setTimeout(checkLoop, 100);
//window.requestAnimationFrame(renderFrame);
}

function doInit() {
let constraints = {
audio: {
sampleRate: 16000,
channelCount: 1,
echoCancellation: false,
autoGainControl: false,
noiseSuppression: false
}
};

let mediaInput = navigator.mediaDevices.getUserMedia( constraints );

if (isInitialized == false) {
Module._do_init();
document.getElementById("butInit").disabled = true;
document.getElementById("description").hidden = true;
isInitialized = true;
}

var x = document.getElementById("canvas");
x.hidden = false;
}

//function renderFrame() {
// window.requestAnimationFrame(renderFrame);
//}

function dropHandler(event) {
// Prevent default behavior (Prevent file from being opened)
event.preventDefault();

// fetch FileList object
var files = event.target.files || event.dataTransfer.files;

// process all File objects
for (var i = 0, f; f = files[i]; i++) {
ParseFile(f);
}
}

function ParseFile(file) {
console.log(
"<p>File information: <strong>" + file.name +
"</strong> type: <strong>" + file.type +
"</strong> size: <strong>" + file.size +
"</strong> bytes</p>"
);

var reader = new FileReader();
reader.onload = function(event) {
var buf = new Uint8Array(reader.result);
var stream = FS.open("record.kbd", "w");
FS.write(stream, buf, 0, buf.length, 0);
FS.close(stream);

Module._do_reload();
}
reader.readAsArrayBuffer(file);
}

function offerFileAsDownload(filename, mime) {
mime = mime || "application/octet-stream";

let content = FS.readFile(filename);
console.log(`Offering download of "${filename}", with ${content.length} bytes...`);

var a = document.createElement('a');
a.download = filename;
a.href = URL.createObjectURL(new Blob([content], {type: mime}));
a.style.display = 'none';

document.body.appendChild(a);
a.click();
setTimeout(() => {
document.body.removeChild(a);
URL.revokeObjectURL(a.href);
}, 2000);
}

var Module = {
arguments: ["record.kbd", "./data"],
preRun: [(function() {
}) ],
postRun: [(function () {
init();
})
],
canvas: (function() {
var canvas = document.getElementById('canvas');
//canvas.style.marginLeft = "-230px";
canvas.addEventListener("webglcontextlost", function(e) { alert('WebGL context lost. You will need to reload the page.'); e.preventDefault(); }, false);

return canvas;
})(),
print: (function() {
return function(text) {
text = Array.prototype.slice.call(arguments).join(' ');
console.log(text);
};
})(),
printErr: function(text) {
text = Array.prototype.slice.call(arguments).join(' ');
console.error(text);
},
setStatus: function(text) {
console.log("status: " + text);
},
monitorRunDependencies: function(left) {
}
};
window.onerror = function() {
document.getElementById("download-info").innerHTML = "Failed to initialize the WASM module. Your browser might not be supported.";
document.getElementById('download-info').style.color='red';
console.log("onerror: " + event);
};

</script>

<script async type="text/javascript" src="@[email protected]"></script>
</body>
</html>
Loading

0 comments on commit 7706c48

Please sign in to comment.