Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

支持微软登录和自动登录 #21

Merged
merged 2 commits into from
Mar 5, 2022
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,4 @@ PCRC.spec
tools/__RFETMP__
tools/protocol
temp_recording/
/TOKEN
2 changes: 2 additions & 0 deletions config.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
"online_mode": false,
"username": "bot_PCRC",
"password": "secret",
"micro_token": "",
"auto": false,
"address": "localhost",
"port": 25565,
"server_name": "SECRET SERVER",
Expand Down
4 changes: 4 additions & 0 deletions readme_cn.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,10 @@ PCRC 目前支持连接官服原版 Minecraft 服务端,支持以下版本:

`password`: 用于正版登录时的 Minecraft 账号的密码

`micro_token`: 微软登录token,用于微软登录。不填写则使用账号密码登录。获取方式:将`micro_token`填写为任意字符串,如`123`。将输出的网址在浏览器中打开,登录 Microsoft 账号。登录成功后,网页将重定向至空白页面。复制网址中的code参数再次填入。(注意不要包含后面的lc参数)

`auto`: 是否开启自动登录,不影响用户名密码登录。需要 TOKEN 文件(微软登录成功后会自动生成,并把此选项自动改为`true`)

`address`: Minecraft 服务器的 IP 地址

`port`: Minecraft 服务器的端口
Expand Down
2 changes: 2 additions & 0 deletions utils/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
"online_mode": false,
"username": "bot_PCRC",
"password": "secret",
"micro_token": "",
"auto": false,
"address": "localhost",
"port": 20000,
"server_name": "SECRET SERVER",
Expand Down
10 changes: 10 additions & 0 deletions utils/pycraft/authentication.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import json
import uuid
from .exceptions import YggdrasilError
from .microsoft_authentication import get_login_info

#: The base url for Ygdrassil requests
AUTH_SERVER = "https://authserver.mojang.com"
Expand Down Expand Up @@ -133,6 +134,15 @@ def authenticate(self, username, password, invalidate_previous=False):

return True

def microsoft_authenticate(self, microsoftToken: str):
resp = get_login_info(microsoftToken)
self.username = resp[2]
self.access_token = resp[0]
self.client_token = uuid.uuid4().hex
self.profile.id_ = resp[1]
self.profile.name = resp[2]
return True

def refresh(self):
"""
Refreshes the `AuthenticationToken`. Used to keep a user logged in
Expand Down
78 changes: 78 additions & 0 deletions utils/pycraft/microsoft_authentication.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import requests
import json
from ..logger import Logger

logger = Logger(name='PCRC')

# https://login.live.com/oauth20_authorize.srf?client_id=00000000402b5328&response_type=code&scope=service%3A%3Auser.auth.xboxlive.com%3A%3AMBI_SSL&redirect_uri=https%3A%2F%2Flogin.live.com%2Foauth20_desktop.srf
def getTokenByAccessCode(i):
context = {"client_id": "00000000402b5328",
"code": i,
"grant_type": "authorization_code",
"redirect_uri": "https://login.live.com/oauth20_desktop.srf",
"scope": "service::user.auth.xboxlive.com::MBI_SSL"}

response = requests.post("https://login.live.com/oauth20_token.srf", context)
return response.json().get("access_token")


def XBL(i):
headers = {'Content-Type': 'application/json', "Accept": "application/json"}
context = {
"Properties": {
"AuthMethod": "RPS",
"SiteName": "user.auth.xboxlive.com",
"RpsTicket": i
},
"RelyingParty": "http://auth.xboxlive.com",
"TokenType": "JWT"
}
response = requests.post("https://user.auth.xboxlive.com/user/authenticate", json.dumps(context), headers=headers)
if response.content == b'':
msg = "microsoft token is expired! Get it from https://login.live.com/oauth20_authorize.srf?client_id=00000000402b5328&response_type=code&scope=service%3A%3Auser.auth.xboxlive.com%3A%3AMBI_SSL&redirect_uri=https%3A%2F%2Flogin.live.com%2Foauth20_desktop.srf"
raise ValueError(msg)
else:
return response.json().get("Token")


def XSL(i):
headers = {'Content-Type': 'application/json', "Accept": "application/json"}
context = {
"Properties": {
"SandboxId": "RETAIL",
"UserTokens": [
i
]
},
"RelyingParty": "rp://api.minecraftservices.com/",
"TokenType": "JWT"
}
response = requests.post("https://xsts.auth.xboxlive.com/xsts/authorize", json.dumps(context), headers=headers)
response = response.json()
return response.get("Token"), response.get("DisplayClaims").get("xui")[0].get("uhs")


def minecraft(token, uhs):
headers = {'Content-Type': 'application/json', "Accept": "application/json"}
context = {
"identityToken": f"XBL3.0 x={uhs};{token}"
}
response = requests.post("https://api.minecraftservices.com/authentication/login_with_xbox", json.dumps(context), headers=headers)

return response.json().get("access_token")


def getUuid(i):
headers = {"Authorization": f"Bearer {i}"}
res = requests.get("https://api.minecraftservices.com/minecraft/profile", headers=headers)
res = res.json()
return res.get("id"), res.get("name")


def get_login_info(accessCode: str) -> list:
Token = getTokenByAccessCode(accessCode)
XBL_token = XBL(Token)
XSL_token, uhs = XSL(XBL_token)
MineToken = minecraft(XSL_token, uhs)
ID, Name = getUuid(MineToken)
return [MineToken, ID, Name]
22 changes: 20 additions & 2 deletions utils/recorder.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import copy
import heapq
import os
import pickle
import shutil
import socket
import threading
Expand Down Expand Up @@ -55,8 +56,24 @@ def __init__(self, config_file, translation_folder):
else:
self.logger.log("Login in online mode")
auth_token = authentication.AuthenticationToken()
auth_token.authenticate(self.config.get('username'), self.config.get('password'))
self.logger.log("Logged in as %s" % auth_token.profile.name)
micro_token = self.config.get('micro_token')

if self.config.get('auto'):
with open("TOKEN", "rb") as f:
auth_token = pickle.load(f)
elif micro_token is not None or micro_token != '':
auth_token.microsoft_authenticate(micro_token)
print("Logged in as %s..." % auth_token.username)

self.config.set_value('micro_token', '')
with open("TOKEN", "wb") as f:
pickle.dump(auth_token, f)
self.config.set_value('auto', True)
self.config.write_to_file()
else:
auth_token.authenticate(self.config.get('username'), self.config.get('password'))
self.logger.log("Logged in as %s" % auth_token.profile.name)

self.config.set_value('username', auth_token.profile.name)
self.connection = Connection(self.config.get('address'), self.config.get('port'),
auth_token=auth_token,
Expand All @@ -65,6 +82,7 @@ def __init__(self, config_file, translation_folder):
allowed_versions=constant.ALLOWED_VERSIONS,
handle_exception=self.onConnectionException
)


self.connection.register_packet_listener(self.onPacketReceived, PycraftPacket)
self.connection.register_packet_listener(self.onPacketSent, PycraftPacket, outgoing=True)
Expand Down