Files
pymetaverse/pymetaverse/login.py
Kyler Eastridge dd67e5096c Initial commit
2025-06-18 00:54:18 -04:00

168 lines
4.2 KiB
Python
Executable File

#!/usr/bin/env python3
import sys
import hashlib
import uuid #For Mac addresses
from . import httpclient
from . import llsd
def getMacAddress():
mac = uuid.getnode()
return ':'.join(("%012X" % mac)[i:i+2] for i in range(0, 12, 2))
def getPlatform():
if sys.platform == "linux" or sys.platform == "linux2":
return "Lnx"
elif sys.platform == "darwin":
return "Mac"
elif sys.platform == "win32":
return "Win"
return "Unk"
#Convenience name
OPTIONS_NONE = []
#Enough to get us most capability out of the grid without restrictions
OPTIONS_MINIMAL = [
"adult_compliant",
]
#Normal stuff
OPTIONS_MOST = [
"inventory-root",
"inventory-lib-root",
"inventory-lib-owner",
"display_names",
"adult_compliant",
"advanced-mode",
"max_groups",
"max-agent-groups",
"map-server-url",
"login-flags",
]
#This may take longer to log in
OPTIONS_FULL = [
"inventory-root",
"inventory-skeleton",
"inventory-meat",
"inventory-skel-targets",
"inventory-lib-root",
"inventory-lib-owner",
"inventory-skel-lib",
"inventory-meat-lib",
"initial-outfit",
"gestures",
"display_names",
"event_categories",
"event_notifications",
"classified_categories",
"adult_compliant",
"buddy-list",
"newuser-config",
"ui-config",
"advanced-mode",
"max_groups",
"max-agent-groups",
"map-server-url",
"voice-config",
"tutorial_setting",
"login-flags",
"global-textures",
#"god-connect", #lol no
]
#WARNING: Not actually async yet! But make it a async request to allow it to be
#done so in the future!
async def Login(username, password,
start = "last",
options = None,
grid = "https://login.agni.lindenlab.com/cgi-bin/login.cgi",
isBot = True
):
if len(username) == 1:
username = (username[0], "resident")
#WARNING:
# Falsifying this is a violation of the Terms of Service
mac = getMacAddress()
platform = getPlatform()
#WARNING:
# Deviating from this format MAY be a violation of the Terms of Service
id0 = hashlib.md5("{}:{}:{}".format(
platform,
mac,
sys.version
).encode("latin")
).hexdigest()
if options == None:
options = OPTIONS_MOST
requestBody = llsd.llsdEncode({
#Credentials
"first": username[0],
"last": username[1],
"passwd": "$1$" + hashlib.md5(password.encode("latin")).hexdigest(),
#"web_login_key": "",
#OS information
"platform": platform,
"platform_version": sys.version,
#Viewer information
"channel": "pymetaverse",
"version": "Testing", #TODO: Change this to metaverse.__VERSION__
#"major": 0,
#"minor": 0,
#"patch": 0,
#"build": 0,
#Machine information
"mac": mac, #WARNING: Falsifying this is a violation of the Terms of Service
"id0": id0, #WARNING: Falsifying this is a violation of the Terms of Service
#"viewer_digest": "",
#Ignore messages for now
"skipoptional": True,
"agree_to_tos": True,
"read_critical": True,
#Viewer options
"extended_errors": True,
"options": options,
"agent_flags": 2 if isBot else 0, #Bitmask, we are a bot, so set bit 2 to true,
"start": start,
#"functions": "", #No idea what this does
#Login error tracking
"last_exec_event": 0,
#"last_exec_froze": False,
#"last_exec_duration": 0,
#For proxied connections apparently:
#"service_proxy_ip": "",
"token": "",
"mfa_hash": ""
})
async with httpclient.HttpClient() as session:
async with await session.post(grid, data = requestBody, headers = {
"Content-Type": "application/llsd+xml"
}) as response:
return llsd.llsdDecode(await response.read())