-
-
Notifications
You must be signed in to change notification settings - Fork 39
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
4e07f1d
commit 4532052
Showing
2 changed files
with
49 additions
and
150 deletions.
There are no files selected for viewing
This file contains 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
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,160 +2,43 @@ | |
|
||
{% block libs %} | ||
{{ super() }} | ||
<script src="https://cdn.jsdelivr.net/pyodide/v0.19.1/full/pyodide.js"></script> | ||
<script src="https://cdn.jsdelivr.net/pyodide/v0.19.1/full/pyodide.asm.js"></script> | ||
<script src="https://cdn.jsdelivr.net/npm/jquery"></script> | ||
<script src="https://cdn.jsdelivr.net/npm/[email protected]/js/jquery.terminal.min.js"></script> | ||
<link | ||
href="https://cdn.jsdelivr.net/npm/[email protected]/css/jquery.terminal.min.css" | ||
rel="stylesheet" | ||
/> | ||
|
||
<style> | ||
.terminal { | ||
--size: 1.5; | ||
--color: rgba(255, 255, 255, 0.8); | ||
} | ||
#iocText { | ||
width: 100%; | ||
height: 7rem; | ||
} | ||
</style> | ||
|
||
<script src="https://cdn.jsdelivr.net/pyodide/v0.23.2/full/pyodide.js"></script> | ||
|
||
<script> | ||
"use strict"; | ||
function sleep(s) { | ||
return new Promise((resolve) => setTimeout(resolve, s)); | ||
} | ||
|
||
var pyodide = undefined; | ||
async function main() { | ||
globalThis.pyodide = await loadPyodide({ | ||
indexURL: "https://cdn.jsdelivr.net/pyodide/v0.19.1/full/", | ||
}); | ||
let namespace = pyodide.globals.get("dict")(); | ||
pyodide.runPython( | ||
` | ||
import sys | ||
from pyodide import to_js | ||
from pyodide.console import PyodideConsole, repr_shorten, BANNER | ||
import __main__ | ||
BANNER = "Welcome to the Pyodide terminal emulator 🐍\\n" + BANNER | ||
pyconsole = PyodideConsole(__main__.__dict__) | ||
async def await_fut(fut): | ||
return to_js([await fut], depth=1) | ||
def clear_console(): | ||
pyconsole.buffer = [] | ||
`, | ||
namespace | ||
); | ||
let repr_shorten = namespace.get("repr_shorten"); | ||
let banner = namespace.get("BANNER"); | ||
let await_fut = namespace.get("await_fut"); | ||
let pyconsole = namespace.get("pyconsole"); | ||
let clear_console = namespace.get("clear_console"); | ||
namespace.destroy(); | ||
|
||
let ps1 = ">>> ", | ||
ps2 = "... "; | ||
|
||
async function lock() { | ||
let resolve; | ||
let ready = term.ready; | ||
term.ready = new Promise((res) => (resolve = res)); | ||
await ready; | ||
return resolve; | ||
} | ||
|
||
async function interpreter(command) { | ||
let unlock = await lock(); | ||
term.pause(); | ||
// multiline should be splitted (useful when pasting) | ||
for (const c of command.split("\n")) { | ||
let fut = pyconsole.push(c); | ||
term.set_prompt(fut.syntax_check === "incomplete" ? ps2 : ps1); | ||
switch (fut.syntax_check) { | ||
case "syntax-error": | ||
term.error(fut.formatted_error.trimEnd()); | ||
continue; | ||
case "incomplete": | ||
continue; | ||
case "complete": | ||
break; | ||
default: | ||
throw new Error(`Unexpected type ${ty}`); | ||
} | ||
// In Javascript, await automatically also awaits any results of | ||
// awaits, so if an async function returns a future, it will await | ||
// the inner future too. This is not what we want so we | ||
// temporarily put it into a list to protect it. | ||
let wrapped = await_fut(fut); | ||
// complete case, get result / error and print it. | ||
try { | ||
let [value] = await wrapped; | ||
if (value !== undefined) { | ||
term.echo( | ||
repr_shorten.callKwargs(value, { | ||
separator: "\n[[;orange;]<long output truncated>]\n", | ||
}) | ||
); | ||
} | ||
if (pyodide.isPyProxy(value)) { | ||
value.destroy(); | ||
} | ||
} catch (e) { | ||
if (e.constructor.name === "PythonError") { | ||
term.error(fut.formatted_error.trimEnd()); | ||
} else { | ||
throw e; | ||
} | ||
} finally { | ||
fut.destroy(); | ||
wrapped.destroy(); | ||
} | ||
} | ||
term.resume(); | ||
await sleep(10); | ||
unlock(); | ||
} | ||
|
||
let term = $("#terminal").terminal(interpreter, { | ||
greetings: banner, | ||
prompt: ps1, | ||
completionEscape: false, | ||
convertLinks: false, | ||
completion: function (command, callback) { | ||
callback(pyconsole.complete(command).toJs()[0]); | ||
}, | ||
keymap: { | ||
"CTRL+C": async function (event, original) { | ||
clear_console(); | ||
term.echo_command(); | ||
term.echo("KeyboardInterrupt"); | ||
term.set_command(""); | ||
term.set_prompt(ps1); | ||
}, | ||
}, | ||
}); | ||
|
||
// startup commands | ||
interpreter("print('')\nimport micropip\nmicropip.install('ioc-finder')\nprint('ioc-finder succesfully installed 🎉')"); | ||
pyodide = await loadPyodide(); | ||
await pyodide.loadPackage("micropip"); | ||
pyodide.runPython("import json"); | ||
await pyodide.runPython("import micropip"); | ||
await pyodide.runPython("micropip.install('ioc-finder')"); | ||
await pyodide.runPython("from ioc_finder import find_iocs"); | ||
|
||
pyodide.runPython("print('ioc-finder succesfully installed 🎉')"); | ||
document.getElementById('parseButton').disabled = false; | ||
} | ||
main(); | ||
|
||
window.term = term; | ||
pyconsole.stdout_callback = (s) => term.echo(s, { newline: false }); | ||
pyconsole.stderr_callback = (s) => { | ||
term.error(s.trimEnd()); | ||
}; | ||
term.ready = Promise.resolve(); | ||
pyodide._module.on_fatal = async (e) => { | ||
term.error( | ||
"Pyodide has suffered a fatal error. Please report this to the Pyodide maintainers." | ||
); | ||
term.error("The cause of the fatal error was:"); | ||
term.error(e); | ||
term.error("Look in the browser console for more details."); | ||
await term.ready; | ||
term.pause(); | ||
await sleep(15); | ||
term.pause(); | ||
}; | ||
async function reload() { | ||
document.getElementById('parseButton').disabled = true; | ||
document.getElementById('output').innerHTML = ''; | ||
document.getElementById('iocText').focus(); | ||
main(); | ||
} | ||
|
||
window.console_ready = main(); | ||
async function parseIOCs() { | ||
const input = document.getElementById('iocText').value.trim(); | ||
const r = await pyodide.runPython(`json.dumps(find_iocs("""${input}"""), indent=4, sort_keys=True)`); | ||
document.getElementById('output').innerHTML = r; | ||
} | ||
</script> | ||
{% endblock %} |