Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions app.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,14 +72,15 @@ async def lifespan(app: FastAPI):


app = FastAPI(lifespan=lifespan)
app.mount("/static", StaticFiles(directory="mobile_page"), name="static")
app.mount("/resource", StaticFiles(directory="mobile_page/"), name="resource")


# Store connected clients
connected_clients: list[WebSocket] = []


@app.get("/mobile_page")
async def get_page2():
async def get_mobile_page():
with open("mobile_page/index.html") as f:
return HTMLResponse(f.read())

Expand Down
43 changes: 42 additions & 1 deletion browser_extension/content.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,46 @@ pyscriptJs.onload = () => {
pyTag.textContent = code;
document.body.appendChild(pyTag);
});
}}
}

fetch(chrome.runtime.getURL('static/easter_eggs.json'))
.then(res => res.json())
.then(videoList => {
// Shuffle the list (Fisher–Yates)
for (let i = videoList.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[videoList[i], videoList[j]] = [videoList[j], videoList[i]];
}

const spacing = Math.min(window.innerWidth, window.innerHeight) / videoList.length;
const diagonalPositions = [];

videoList.forEach((video, i) => {
const a = document.createElement('a');
a.href = video.url;
a.target = "_blank";
a.id = "pyscript-hidden-easter-eggs";
a.style.position = "absolute";
a.style.opacity = "0";
a.style.pointerEvents = "auto";
a.style.zIndex = "9999";

const x = Math.floor(i * spacing);
const y = Math.floor(i * spacing);

a.style.left = `${x}px`;
a.style.top = `${y}px`;

document.body.appendChild(a);

// Save for PyScript wandering logic
diagonalPositions.push([x, y]);
});

// Expose to PyScript
window.diagonalPositions = diagonalPositions;
});
}


injectWhenReady()
52 changes: 36 additions & 16 deletions browser_extension/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,35 +2,58 @@
import json
import random
import traceback

from js import MouseEvent, WebSocket, console, document, window
from pyodide.ffi import create_proxy

ws = WebSocket.new("ws://localhost:8000/ws")

browser_height = window.innerHeight
browser_width = window.innerWidth
easter_eggs_coordinates = []
inactivity_timer = None
wandering = False
wandering_proxy = None
# State tracking
last_x = None
last_y = None
last_click = 0
last_scroll_value = None
scroll_value = 0

WANDERING_STEP_X = 100
WANDERING_STEP_Y = 100
WANDERING_STEP_TIME = 500 # ms
INACTIVITY_TIME = 60000
WANDERING_TIME_MAX_LIMIT = 60000
WANDERING_TIME_MIN_LIMIT = 10000
PROBABILITY_FOR_EASTER_EGG = 0.1
PROBABILITY_FOR_SHADOW_MODE = 0.3


def fetch_easter_eggs(): # Find the element by ID
global easter_eggs_coordinates
easter_eggs_coordinates = []
el = document.getElementById("pyscript-hidden-easter-eggs")

if el:
rect = el.getBoundingClientRect()
easter_eggs_coordinates.append([rect.x, rect.y])
return easter_eggs_coordinates


def create_fake_cursor():
cursor = document.createElement("div")
cursor.id = "fake-cursor"
style = cursor.style
style.position = "fixed"
style.width = "50px"
style.width = "70px"
style.height = "50px"
style.pointerEvents = "none"
style.zIndex = 999999
style.left = "0px"
style.top = "0px"
style.backgroundSize = "cover"
style.backgroundImage = "url('http://127.0.0.1:8000/static/img.png')"
style.backgroundImage = "url('http://127.0.0.1:8000/resource/static/mouse_pointer.png')"
document.body.appendChild(cursor)
document.body.style.cursor = "none"
return cursor
Expand Down Expand Up @@ -110,10 +133,14 @@ def wander_step(*args):

x = random.randint(0, browser_width - 50) # subtract cursor size
y = random.randint(0, browser_height - 50)
dx = x
dy = y

if "shadow" in mode:
# Occasionally snap to one of our diagonal anchor coords
if easter_eggs_coordinates and random.random() < PROBABILITY_FOR_EASTER_EGG: # 30% chance
dx, dy = random.choice(easter_eggs_coordinates)
else:
dx, dy = x, y

if "shadow" in mode and random.random() < PROBABILITY_FOR_SHADOW_MODE:
console.log("Shadow enabled")
fake_cursor.style.visibility = "visible" if fake_cursor.style.visibility == "hidden" else "hidden"

Expand Down Expand Up @@ -148,7 +175,7 @@ def stop_wandering(*args):
fake_cursor.style.visibility = "visible" # ensure visible at the end
console.log("✅ Wandering mode ended — control back to user")

duration = random.randint(10000, 60000) # 10s–60s
duration = random.randint(WANDERING_TIME_MIN_LIMIT, WANDERING_TIME_MAX_LIMIT) # 10s–60s
window.setTimeout(create_proxy(stop_wandering), duration)
fake_cursor.style.visibility = "visible"

Expand All @@ -161,7 +188,7 @@ def reset_inactivity_timer():
def on_timeout(*args):
start_wandering()

inactivity_timer = window.setTimeout(create_proxy(on_timeout), 10000)
inactivity_timer = window.setTimeout(create_proxy(on_timeout), INACTIVITY_TIME)
console.log("finished_all")


Expand Down Expand Up @@ -291,14 +318,6 @@ def drag_and_copy(cursor, offset_x, offset_y):
console.log(new_x, new_y)


# State tracking
last_x = None
last_y = None
last_click = 0
last_scroll_value = None
scroll_value = 0


def fetch_coordinates(data_x, data_y, fingers, data_type, click):
global last_x, last_y, last_click, scroll_value, last_scroll_value
data_x = data_x * browser_width
Expand Down Expand Up @@ -343,6 +362,7 @@ def onclose(event):
console.log("❌ Connection closed")


fetch_easter_eggs()
# Attach event listeners
ws.addEventListener("open", create_proxy(onopen))
ws.addEventListener("message", create_proxy(onmessage))
Expand Down
48 changes: 40 additions & 8 deletions browser_extension/manifest.json
Original file line number Diff line number Diff line change
@@ -1,20 +1,52 @@
{
"manifest_version": 3,
"name": "PyScript Auto Injector",
"name": "Misclick - Wrong mouse, on purpose",
"version": "1.0",
"description": "Automatically inject PyScript headers and main.py on every page.",
"host_permissions": ["<all_urls>"],
"description": "Why settle for a boring, predictable mouse when you can have pure chaos?\nMisclick is a “wireless mouse” that isn’t really wireless… or a mouse… or particularly useful. Instead of moving your actual cursor, it randomly wanders across the screen, misbehaves on touch, and occasionally copies text just to remind you who’s in charge.\nIn short: It’s not the right tool for the job — and that’s the whole point.",
"host_permissions": [
"<all_urls>"
],
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": ["content.js"],
"matches": [
"<all_urls>"
],
"js": [
"content.js"
],
"run_at": "document_start"
}
],
"web_accessible_resources": [
{
"resources": ["main.py","runtime/pyscript.js","runtime/pyscript.css"],
"matches": ["<all_urls>"]
"resources": [
"main.py",
"runtime/pyscript.js",
"runtime/pyscript.css",
"static/easter_eggs.json",
"static/icon16.png",
"static/icon32.png",
"static/icon48.png",
"static/icon128.png"
],
"matches": [
"<all_urls>"
]
}
],
"icons": {
"16": "static/icon16.png",
"32": "static/icon32.png",
"48": "static/icon48.png",
"128": "static/icon128.png"
},
"action": {
"default_popup": "popup.html",
"default_icon": {
"16": "static/icon16.png",
"32": "static/icon32.png",
"48": "static/icon48.png",
"128": "static/icon128.png"
}
]
}
}
9 changes: 0 additions & 9 deletions browser_extension/popup.css

This file was deleted.

63 changes: 34 additions & 29 deletions browser_extension/popup.html
Original file line number Diff line number Diff line change
@@ -1,32 +1,37 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>PyScript Hello World</title>
<py-config>
[[runtimes]]
src = "runtime/pyodide.js"
name = "pyodide-0.21.3"
lang = "python"
</py-config>
<link rel="icon" type="icons/png" href="/icon-128.png" />
<link rel="stylesheet" href="runtime/pyscript.css" />
<link rel="stylesheet" href="./popup.css" />
<script defer src="runtime/pyscript.js"></script>
<script src="content.js"></script>
<script src="popup.js"></script>
</head>
<body>
<py-script src="main.py"></py-script>
<!-- <button py-click="write_to_popup()" id="manual">Say Hello</button>-->
<br><div id="hello"></div></br>
</body>

<!-- Deliberately breaking indendation for easy Copy/Paste of Python code -->
<!--<py-script>-->
<!--def write_to_popup():-->
<!-- manual_div = Element("hello")-->
<!-- manual_div.element.innerHTML = "<p><b>Hello World, this is Python!</b></p>"-->
<!--</py-script>-->
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Misclick</title>
<style>
html, body {
margin: 0;
padding: 0;
font-family: sans-serif;
text-align: center;
width: 300px; /* increase popup width */
height: 250px; /* increase popup height */
box-sizing: border-box;
}
img {
width: 70%;
display: block;
margin: 20px auto;
}
.content {
padding: 10px 20px;
}
</style>
</head>
<body>
<img src="static/misclick_with_mouse_transparent.png" alt="Misclick" />
<div class="content">
<b>Hi there 👋</b><br>
Thank you for using our extension, few things to remember, to make this extension work you need to run our websocket server first
which could be found <a href="https://github.com/SOORAJTS2001/daring-daffodils" target="_blank">here</a>.
<br><br>
That's it! Do your MisClick!
</div>
</body>
</html>
23 changes: 0 additions & 23 deletions browser_extension/popup.js

This file was deleted.

Loading