This commit is contained in:
copyrighttxt
2026-08-04 18:24:32 -04:00
committed by GitHub
parent cb2bcb56d4
commit e79463ce20
+12 -55
View File
@@ -22,12 +22,9 @@ from app.models.place import Place
from app.models.asset import Asset from app.models.asset import Asset
from app.models.login_records import LoginRecord from app.models.login_records import LoginRecord
from app.models.user_hwid_log import UserHWIDLog from app.models.user_hwid_log import UserHWIDLog
from app.models.user_ban import UserBan
from app.models.admin_permissions import AdminPermissions
from app.models.universe import Universe from app.models.universe import Universe
from app.models.asset_version import AssetVersion from app.models.asset_version import AssetVersion
from app.enums.AssetType import AssetType from app.enums.AssetType import AssetType
from app.enums.BanType import BanType
from app.enums.MembershipType import MembershipType from app.enums.MembershipType import MembershipType
from app.enums.PlaceYear import PlaceYear from app.enums.PlaceYear import PlaceYear
from app.services.gameserver_comm import perform_post from app.services.gameserver_comm import perform_post
@@ -199,7 +196,6 @@ def CreateNewPlaceServer( placeId : int, reserved_server_access_code : str = Non
serverIP = SelectedGameServerObj.serverIP, serverIP = SelectedGameServerObj.serverIP,
serverPort = OpenJobReqJSON["port"], serverPort = OpenJobReqJSON["port"],
serverPlaceId = placeId, serverPlaceId = placeId,
serverRunningTime = 1,
maxPlayerCount = PlaceObj.maxplayers, maxPlayerCount = PlaceObj.maxplayers,
reservedServerAccessCode = reserved_server_access_code reservedServerAccessCode = reserved_server_access_code
) )
@@ -245,7 +241,7 @@ def GetSuitablePlaceServer( placeId : int ) -> PlaceServer | bool:
except: except:
return False return False
return NewPlaceServerObj return False
GameJoinRoute = Blueprint('gamejoin', __name__, url_prefix='/') GameJoinRoute = Blueprint('gamejoin', __name__, url_prefix='/')
@@ -320,48 +316,6 @@ def ReturnPlaceLauncher( message : str, status : int, authenticated_userid : int
response.headers["Cache-Control"] = "no-cache, no-store, must-revalidate" response.headers["Cache-Control"] = "no-cache, no-store, must-revalidate"
return response return response
def BanUsersForSharedHwid(hwid: str, triggering_user_id: int | None = None) -> bool:
MatchingHWIDLogs : list[UserHWIDLog] = UserHWIDLog.query.filter_by(hwid=hwid).distinct(UserHWIDLog.user_id).all()
if len(MatchingHWIDLogs) < 2:
return False
MatchingUserIds = {log.user_id for log in MatchingHWIDLogs if log.user_id is not None}
if len(MatchingUserIds) < 2:
return False
for user_id in MatchingUserIds:
UserObj : User | None = User.query.filter_by(id=user_id).first()
if UserObj is None:
continue
if AdminPermissions.query.filter_by(userid=UserObj.id).first() is not None:
return False
for user_id in MatchingUserIds:
UserObj : User | None = User.query.filter_by(id=user_id).first()
if UserObj is None:
continue
if UserObj.accountstatus != 1:
continue
ExistingActiveBan : UserBan | None = UserBan.query.filter_by(userid=UserObj.id, acknowledged=False).order_by(UserBan.id.desc()).first()
if ExistingActiveBan is not None:
continue
BanObj = UserBan(
userid=UserObj.id,
author_userid=1,
reason="Alting is not permitted on NEXIUM, contact us if you believe this is unfair",
ban_type=BanType.Deleted,
moderator_note=f"Automatic HWID alt ban for shared HWID {hwid}",
expires_at=None
)
db.session.add(BanObj)
UserObj.accountstatus = 3
if MatchingUserIds:
db.session.commit()
return True
@GameJoinRoute.route('/game/PlaceLauncher.ashx', methods=['GET', 'POST']) @GameJoinRoute.route('/game/PlaceLauncher.ashx', methods=['GET', 'POST'])
@GameJoinRoute.route('/Game/PlaceLauncher.ashx', methods=['GET', 'POST']) @GameJoinRoute.route('/Game/PlaceLauncher.ashx', methods=['GET', 'POST'])
@GameJoinRoute.route('/game/placelauncher.ashx', methods=['GET', 'POST']) @GameJoinRoute.route('/game/placelauncher.ashx', methods=['GET', 'POST'])
@@ -369,7 +323,7 @@ def BanUsersForSharedHwid(hwid: str, triggering_user_id: int | None = None) -> b
@csrf.exempt @csrf.exempt
def placelauncher(): def placelauncher():
if not websiteFeatures.GetWebsiteFeature("GameJoinAPI"): if not websiteFeatures.GetWebsiteFeature("GameJoinAPI"):
logging.warning("opsec") return ReturnPlaceLauncher("GameJoinAPI is disabled", 12)
AuthenticatdUser = None AuthenticatdUser = None
placeid = request.args.get( key = 'placeId', default = None, type = int) or request.args.get( key = 'placeid', default = None, type = int) placeid = request.args.get( key = 'placeId', default = None, type = int) or request.args.get( key = 'placeid', default = None, type = int)
@@ -392,6 +346,12 @@ def placelauncher():
if authticketInfo is None and AuthenticatdUser is None: if authticketInfo is None and AuthenticatdUser is None:
return ReturnPlaceLauncher("Invalid authentication ticket", 12) return ReturnPlaceLauncher("Invalid authentication ticket", 12)
#UserIPHash = hashlib.md5(get_remote_address().encode("utf-8")).hexdigest()
#LoginRecords : list[LoginRecord] = LoginRecord.query.filter(LoginRecord.ip == UserIPHash).distinct(LoginRecord.userid).all()
#for record in LoginRecords:
# if record.User.accountstatus != 1:
# return ReturnPlaceLauncher("Invalid authentication ticket", 12)
userId = int(authticketInfo) if authticketInfo is not None else AuthenticatdUser.id userId = int(authticketInfo) if authticketInfo is not None else AuthenticatdUser.id
if PlaceServerPlayer.query.filter_by(userid=userId).first() is not None and not isTeleport: if PlaceServerPlayer.query.filter_by(userid=userId).first() is not None and not isTeleport:
CurrentPlaceServerPlayerObj : PlaceServerPlayer = PlaceServerPlayer.query.filter_by(userid=userId).first() CurrentPlaceServerPlayerObj : PlaceServerPlayer = PlaceServerPlayer.query.filter_by(userid=userId).first()
@@ -428,9 +388,6 @@ def placelauncher():
redis_controller.delete(f"hwid:{str(Tracking_Cookie)}") redis_controller.delete(f"hwid:{str(Tracking_Cookie)}")
if BanUsersForSharedHwid(UserHWIDHash, UserObj.id):
return ReturnPlaceLauncher("Invalid session", 12)
UserMembershipStatus : MembershipType = GetUserMembership(UserObj) UserMembershipStatus : MembershipType = GetUserMembership(UserObj)
if UniverseObj.bc_required and UserMembershipStatus == MembershipType.NonBuildersClub: if UniverseObj.bc_required and UserMembershipStatus == MembershipType.NonBuildersClub:
return ReturnPlaceLauncher("Builders Club required", 12) return ReturnPlaceLauncher("Builders Club required", 12)
@@ -462,10 +419,11 @@ def placelauncher():
if PlaceServerObj is False: if PlaceServerObj is False:
logging.info(f"Placelauncher.ashx : {str(placeid)} : {UserObj.username} [{UserObj.id}] : No available place servers found yet") logging.info(f"Placelauncher.ashx : {str(placeid)} : {UserObj.username} [{UserObj.id}] : No available place servers found yet")
return ReturnPlaceLauncher(None, 1, authenticated_userid=userId) return ReturnPlaceLauncher(None, 1, authenticated_userid=userId)
redis_controller.delete(f"authticket:{ticket}")
authenticatedTicketUUID = str(uuid.uuid4()) authenticatedTicketUUID = str(uuid.uuid4())
redis_controller.setex(f"place:{placeid}:ticket:{authenticatedTicketUUID}", 60, json.dumps({"id": userId, "jobid": str(PlaceServerObj.serveruuid)})) redis_controller.setex(f"place:{placeid}:ticket:{authenticatedTicketUUID}", 60, json.dumps({"id": userId, "jobid": str(PlaceServerObj.serveruuid)}))
authticket = ''.join(random.choices(string.ascii_uppercase + string.digits, k=256)) authticket = ''.join(secrets.choice(string.ascii_uppercase + string.digits) for _ in range(256))
redis_controller.set(f"authticket:{authticket}", userId, 60*10) redis_controller.set(f"authticket:{authticket}", userId, 60*10)
resp = make_response(jsonify({ resp = make_response(jsonify({
"jobId": PlaceServerObj.serveruuid, "jobId": PlaceServerObj.serveruuid,
@@ -613,7 +571,7 @@ def GenerateClientTicket( UserObj : User, JobId : str, CharacterURL : str = None
if TicketVersion == 2: if TicketVersion == 2:
CharacterURL = str(UserObj.id) CharacterURL = str(UserObj.id)
elif TicketVersion == 1: elif TicketVersion == 1:
CharacterURL = Config.BaseURL + "/Asset/CharacterFetch.ashx?userId=" + str(UserObj.id) # f"http://www.nexium.fit/v1.1/avatar-fetch?userId={str(UserObj.id)}&placeId={str(PlaceId)}" CharacterURL = Config.BaseURL + "/Asset/CharacterFetch.ashx?userId=" + str(UserObj.id) # f"http://www.vortexi.cc/v1.1/avatar-fetch?userId={str(UserObj.id)}&placeId={str(PlaceId)}"
elif TicketVersion == 4: elif TicketVersion == 4:
CharacterURL = f"http://www.nexium.fit/v1/avatar-fetch?userId={str(UserObj.id)}&placeId={str(PlaceId)}" CharacterURL = f"http://www.nexium.fit/v1/avatar-fetch?userId={str(UserObj.id)}&placeId={str(PlaceId)}"
@@ -665,8 +623,7 @@ def join():
PlaceObj : Place = Place.query.filter_by(placeid=placeid).first() PlaceObj : Place = Place.query.filter_by(placeid=placeid).first()
AssetObj : Asset = Asset.query.filter_by(id=placeid).first() AssetObj : Asset = Asset.query.filter_by(id=placeid).first()
UniverseObj : Universe = Universe.query.filter_by(id=PlaceObj.parent_universe_id).first() UniverseObj : Universe = Universe.query.filter_by(id=PlaceObj.parent_universe_id).first()
if UniverseObj.place_year == PlaceYear.Sixteen:
return 'Who is bro', 400
ClientTicket = GenerateClientTicket(UserObj, jobid, TicketVersion = 1 if UniverseObj.place_year in [PlaceYear.Sixteen, PlaceYear.Fourteen] else ( 2 if UniverseObj.place_year == PlaceYear.Eighteen else 4), PlaceId = placeid) ClientTicket = GenerateClientTicket(UserObj, jobid, TicketVersion = 1 if UniverseObj.place_year in [PlaceYear.Sixteen, PlaceYear.Fourteen] else ( 2 if UniverseObj.place_year == PlaceYear.Eighteen else 4), PlaceId = placeid)
AuthenticationTicket = auth.CreateToken(UserObj.id, get_remote_address() , (60*60*24) ) AuthenticationTicket = auth.CreateToken(UserObj.id, get_remote_address() , (60*60*24) )