Initial commit
This commit is contained in:
commit
9feb845d3c
7 changed files with 333 additions and 0 deletions
131
.gitignore
vendored
Normal file
131
.gitignore
vendored
Normal file
|
@ -0,0 +1,131 @@
|
|||
# Byte-compiled / optimized / DLL files
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
|
||||
# C extensions
|
||||
*.so
|
||||
|
||||
# Distribution / packaging
|
||||
.Python
|
||||
build/
|
||||
develop-eggs/
|
||||
dist/
|
||||
downloads/
|
||||
eggs/
|
||||
.eggs/
|
||||
lib/
|
||||
lib64/
|
||||
parts/
|
||||
sdist/
|
||||
var/
|
||||
wheels/
|
||||
pip-wheel-metadata/
|
||||
share/python-wheels/
|
||||
*.egg-info/
|
||||
.installed.cfg
|
||||
*.egg
|
||||
MANIFEST
|
||||
|
||||
# PyInstaller
|
||||
# Usually these files are written by a python script from a template
|
||||
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||
*.manifest
|
||||
*.spec
|
||||
|
||||
# Installer logs
|
||||
pip-log.txt
|
||||
pip-delete-this-directory.txt
|
||||
|
||||
# Unit test / coverage reports
|
||||
htmlcov/
|
||||
.tox/
|
||||
.nox/
|
||||
.coverage
|
||||
.coverage.*
|
||||
.cache
|
||||
nosetests.xml
|
||||
coverage.xml
|
||||
*.cover
|
||||
*.py,cover
|
||||
.hypothesis/
|
||||
.pytest_cache/
|
||||
|
||||
# Translations
|
||||
*.mo
|
||||
*.pot
|
||||
|
||||
# Django stuff:
|
||||
*.log
|
||||
local_settings.py
|
||||
db.sqlite3
|
||||
db.sqlite3-journal
|
||||
|
||||
# Flask stuff:
|
||||
instance/
|
||||
.webassets-cache
|
||||
|
||||
# Scrapy stuff:
|
||||
.scrapy
|
||||
|
||||
# Sphinx documentation
|
||||
docs/_build/
|
||||
|
||||
# PyBuilder
|
||||
target/
|
||||
|
||||
# Jupyter Notebook
|
||||
.ipynb_checkpoints
|
||||
|
||||
# IPython
|
||||
profile_default/
|
||||
ipython_config.py
|
||||
|
||||
# pyenv
|
||||
.python-version
|
||||
|
||||
# pipenv
|
||||
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
||||
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
||||
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
||||
# install all needed dependencies.
|
||||
#Pipfile.lock
|
||||
|
||||
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
|
||||
__pypackages__/
|
||||
|
||||
# Celery stuff
|
||||
celerybeat-schedule
|
||||
celerybeat.pid
|
||||
|
||||
# SageMath parsed files
|
||||
*.sage.py
|
||||
|
||||
# Environments
|
||||
.env
|
||||
.venv
|
||||
env/
|
||||
venv/
|
||||
ENV/
|
||||
env.bak/
|
||||
venv.bak/
|
||||
|
||||
# Spyder project settings
|
||||
.spyderproject
|
||||
.spyproject
|
||||
|
||||
# Rope project settings
|
||||
.ropeproject
|
||||
|
||||
# mkdocs documentation
|
||||
/site
|
||||
|
||||
# mypy
|
||||
.mypy_cache/
|
||||
.dmypy.json
|
||||
dmypy.json
|
||||
|
||||
# Pyre type checker
|
||||
.pyre/
|
||||
|
||||
token.txt
|
23
README.md
Normal file
23
README.md
Normal file
|
@ -0,0 +1,23 @@
|
|||
# Computer kill switch
|
||||
|
||||
This program is a PC kill switch Telegram bot. It is a project for New Generation.
|
||||
|
||||
## Security notice
|
||||
This program provides no access control, so anyone knowing the bot username is able to use it.
|
||||
|
||||
## Features
|
||||
- disabling and re-enabling keyboard and mouse input
|
||||
- locking the screen
|
||||
- formatting partitions
|
||||
- playing text-to-speech messages
|
||||
|
||||
## Limitations
|
||||
- input lock resets if Control-Alt-Delete is pressed
|
||||
- volumes used by some software at the time of request cannot be formatted
|
||||
- works on Windows only
|
||||
|
||||
## Usage
|
||||
Before starting the bot, its token must be put into token.txt file with no newlines. Administrator privileges are required so that the bot is able to disable input and format partitions. Once the bot is started, send /start to its account on Telegram to see what can be done.
|
||||
|
||||
## Licensing
|
||||
All code in this repository is Unlicensed, see UNLICENSE.
|
24
UNLICENSE
Normal file
24
UNLICENSE
Normal file
|
@ -0,0 +1,24 @@
|
|||
This is free and unencumbered software released into the public domain.
|
||||
|
||||
Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||
distribute this software, either in source code form or as a compiled
|
||||
binary, for any purpose, commercial or non-commercial, and by any
|
||||
means.
|
||||
|
||||
In jurisdictions that recognize copyright laws, the author or authors
|
||||
of this software dedicate any and all copyright interest in the
|
||||
software to the public domain. We make this dedication for the benefit
|
||||
of the public at large and to the detriment of our heirs and
|
||||
successors. We intend this dedication to be an overt act of
|
||||
relinquishment in perpetuity of all present and future rights to this
|
||||
software under copyright law.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
For more information, please refer to <http://unlicense.org/>
|
15
main.py
Normal file
15
main.py
Normal file
|
@ -0,0 +1,15 @@
|
|||
# Project: Telegram PC kill switch bot
|
||||
# Author: Stanislav Mykhailenko
|
||||
# License: Unlicense
|
||||
|
||||
import ctypes, sys
|
||||
from tg import startBot
|
||||
|
||||
def main() -> None:
|
||||
if ctypes.windll.shell32.IsUserAnAdmin():
|
||||
startBot()
|
||||
else:
|
||||
ctypes.windll.shell32.ShellExecuteW(None, "runas", sys.executable, " ".join(sys.argv), None, 1)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
25
payload.py
Normal file
25
payload.py
Normal file
|
@ -0,0 +1,25 @@
|
|||
# Project: Telegram PC kill switch bot
|
||||
# Author: Stanislav Mykhailenko
|
||||
# License: Unlicense
|
||||
|
||||
# This file contains the payloads
|
||||
|
||||
import ctypes, os, pyttsx3
|
||||
|
||||
def enableInput():
|
||||
ctypes.windll.user32.BlockInput(False)
|
||||
|
||||
def disableInput():
|
||||
ctypes.windll.user32.BlockInput(True)
|
||||
|
||||
def lockScreen():
|
||||
ctypes.windll.user32.LockWorkStation()
|
||||
|
||||
def formatVolumes(volumes):
|
||||
for volume in volumes:
|
||||
os.system('format ' + volume + ' /y')
|
||||
|
||||
def playMessage(message):
|
||||
engine = pyttsx3.init()
|
||||
engine.say(message)
|
||||
engine.runAndWait()
|
10
requirements.txt
Normal file
10
requirements.txt
Normal file
|
@ -0,0 +1,10 @@
|
|||
anyio==3.6.2
|
||||
certifi==2022.12.7
|
||||
h11==0.14.0
|
||||
httpcore==0.16.3
|
||||
httpx==0.23.3
|
||||
idna==3.4
|
||||
python-telegram-bot==20.0
|
||||
pyttsx3==2.90
|
||||
rfc3986==1.5.0
|
||||
sniffio==1.3.0
|
105
tg.py
Normal file
105
tg.py
Normal file
|
@ -0,0 +1,105 @@
|
|||
# Project: Telegram PC kill switch bot
|
||||
# Author: Stanislav Mykhailenko
|
||||
# License: Unlicense
|
||||
|
||||
# This file contains Telegram interactions
|
||||
|
||||
from telegram import ReplyKeyboardMarkup, ReplyKeyboardRemove, Update
|
||||
from telegram.ext import Application, CommandHandler, ContextTypes, ConversationHandler, filters, MessageHandler
|
||||
from payload import *
|
||||
import logging
|
||||
from threading import Thread
|
||||
|
||||
logging.basicConfig(
|
||||
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
|
||||
level=logging.INFO
|
||||
)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
ACTION, FORMAT, MESSAGE = range(3)
|
||||
|
||||
def getToken():
|
||||
with open(os.path.realpath(os.path.dirname(__file__)) + '/' + 'token.txt', 'r') as file:
|
||||
return file.read()
|
||||
|
||||
|
||||
async def start(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
|
||||
reply_keyboard = [["Enable input", "Disable input", "Lock screen", "Format volumes", "Play message"]]
|
||||
|
||||
await update.message.reply_text(
|
||||
"Choose your action:",
|
||||
reply_markup=ReplyKeyboardMarkup(
|
||||
reply_keyboard, one_time_keyboard=True, input_field_placeholder="Choose your action"
|
||||
),
|
||||
)
|
||||
|
||||
return ACTION
|
||||
|
||||
async def action(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
|
||||
user = update.message.from_user
|
||||
|
||||
match update.message.text:
|
||||
case "Enable input":
|
||||
logger.info("Got a request from %s to enable input.", user.first_name)
|
||||
enableInput()
|
||||
await update.message.reply_text("Input enabled.", reply_markup=ReplyKeyboardRemove())
|
||||
return ConversationHandler.END
|
||||
case "Disable input":
|
||||
logger.info("Got a request from %s to disable input.", user.first_name)
|
||||
disableInput()
|
||||
await update.message.reply_text("Input disabled.", reply_markup=ReplyKeyboardRemove())
|
||||
return ConversationHandler.END
|
||||
case "Lock screen":
|
||||
logger.info("Got a request from %s to lock screen.", user.first_name)
|
||||
lockScreen()
|
||||
await update.message.reply_text("Screen locked.", reply_markup=ReplyKeyboardRemove())
|
||||
return ConversationHandler.END
|
||||
case "Format volumes":
|
||||
logger.info("Got a request from %s to format volumes.", user.first_name)
|
||||
await update.message.reply_text("Please type a space-separated list of the volumes you want to format.", reply_markup=ReplyKeyboardRemove())
|
||||
return FORMAT
|
||||
case "Play message":
|
||||
logger.info("Got a request from %s to play a message.", user.first_name)
|
||||
await update.message.reply_text("Please type the message you want to play.", reply_markup=ReplyKeyboardRemove())
|
||||
return MESSAGE
|
||||
|
||||
async def format(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
|
||||
user = update.message.from_user
|
||||
|
||||
logger.info("Got a request from %s to format volumes %s.", user.first_name, update.message.text)
|
||||
Thread(target=formatVolumes,args=(update.message.text.split(),)).start()
|
||||
await update.message.reply_text("Command to format the volumes sent.")
|
||||
|
||||
return ConversationHandler.END
|
||||
|
||||
async def message(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
|
||||
user = update.message.from_user
|
||||
logger.info("Got a request from %s to play message %s.", user.first_name, update.message.text)
|
||||
Thread(target=playMessage,args=(update.message.text,)).start()
|
||||
await update.message.reply_text("Command to play the message sent.")
|
||||
|
||||
return ConversationHandler.END
|
||||
|
||||
async def cancel(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
|
||||
user = update.message.from_user
|
||||
logger.info("User %s canceled the conversation.", user.first_name)
|
||||
await update.message.reply_text("Request cancelled.", reply_markup=ReplyKeyboardRemove())
|
||||
|
||||
return ConversationHandler.END
|
||||
|
||||
def startBot():
|
||||
application = Application.builder().token(getToken()).build()
|
||||
|
||||
conv_handler = ConversationHandler(
|
||||
entry_points=[CommandHandler("start", start)],
|
||||
states={
|
||||
ACTION: [MessageHandler(filters.Regex("^(Enable input|Disable input|Lock screen|Format volumes|Play message)$"), action)],
|
||||
FORMAT: [MessageHandler(filters.TEXT & ~filters.COMMAND, format)],
|
||||
MESSAGE: [MessageHandler(filters.TEXT & ~filters.COMMAND, message)],
|
||||
},
|
||||
fallbacks=[CommandHandler("cancel", cancel)],
|
||||
)
|
||||
|
||||
application.add_handler(conv_handler)
|
||||
|
||||
application.run_polling()
|
Reference in a new issue