655 lines
34 KiB
Python
655 lines
34 KiB
Python
from flask import Blueprint, render_template, request, redirect, url_for, flash, make_response, jsonify, abort
|
||
from app.extensions import csrf, redis_controller, get_remote_address
|
||
from app.models.user import User
|
||
from app.models.place import Place
|
||
from app.models.asset import Asset
|
||
from app.models.asset_version import AssetVersion
|
||
from app.models.gameservers import GameServer
|
||
from app.models.universe import Universe
|
||
from app.models.groups import Group, GroupRole, GroupRolePermission
|
||
from app.enums.PlaceRigChoice import PlaceRigChoice
|
||
from app.enums.PlaceYear import PlaceYear
|
||
from app.util.assetversion import GetLatestAssetVersion
|
||
from app.util.textfilter import FilterText
|
||
from app.util import auth
|
||
from app.services import economy, groups
|
||
from app.routes.asset import GenerateTempAuthToken
|
||
from config import Config
|
||
import logging
|
||
import datetime
|
||
|
||
config = Config()
|
||
|
||
ClientInfo = Blueprint('clientinfo', __name__, url_prefix='/')
|
||
|
||
@ClientInfo.route('/GetAllowedSecurityVersions/', methods=['GET'])
|
||
def GetAllowedSecurityVersions():
|
||
return jsonify({
|
||
"data": ["0.360.0pcplayer", "0.450.0pcplayer", "0.463.0pcplayer", "0.0.0.1", "PRAFBERQ", "39f6144dd9288912aea2df1a5a6b7b4d405d8316"]
|
||
})
|
||
|
||
@ClientInfo.route("/GetAllowedMD5Hashes/", methods=['GET'])
|
||
def GetAllowedMD5Hashes():
|
||
apiKey = request.args.get("apiKey", default=None, type=str)
|
||
if apiKey == "dac86da7-a4bc-4bff-8ca4-8b54e1ac925b": # 2021
|
||
return jsonify({
|
||
"data": [
|
||
"a384c8a1fa1f02b7bd4c60313d034cc1",# 2020
|
||
"69957b53e003c89f7a24debab0b50a3a" # 2021
|
||
]
|
||
}), 200
|
||
|
||
return jsonify({
|
||
"data": [
|
||
# 2016
|
||
"3dacdae5eebddad646e5c79378313984",
|
||
# 2018,
|
||
"2e9d56a875ae66f899bd18e4ef660592"
|
||
]
|
||
})
|
||
|
||
@ClientInfo.route('/game/players/<userid>/', methods=['GET'])
|
||
def GetPlayerInfo(userid):
|
||
return jsonify({
|
||
"ChatFilter": "whitelist"
|
||
})
|
||
@ClientInfo.route("/Game/ChatFilter.ashx", methods=["POST"])
|
||
@csrf.exempt
|
||
def ChatFilterAshx():
|
||
try:
|
||
RequestedFilterText = request.data.decode("utf-8")
|
||
except:
|
||
RequestedFilterText = str(request.data)
|
||
|
||
try:
|
||
FilterText(
|
||
Text = RequestedFilterText,
|
||
ReplaceWith = "#",
|
||
ThrowException = True
|
||
)
|
||
return "True"
|
||
except:
|
||
return "False"
|
||
|
||
|
||
@ClientInfo.route("/moderation/filtertext/", methods=['POST'])
|
||
@csrf.exempt
|
||
def FilterTextAPI():
|
||
RequestedFilterText = request.form.get("text", default="", type=str)
|
||
|
||
FilteredText = FilterText(
|
||
Text = RequestedFilterText,
|
||
ReplaceWith = "#",
|
||
ThrowException = False
|
||
)
|
||
|
||
return jsonify({
|
||
"data": {
|
||
"white": FilteredText,
|
||
"black": ""
|
||
}
|
||
})
|
||
|
||
@ClientInfo.route("/v2/moderation/textfilter", methods=['POST'])
|
||
@ClientInfo.route("/moderation/v2/filtertext", methods=['POST'])
|
||
@ClientInfo.route("/moderation/v2/filtertext/", methods=['POST'])
|
||
@csrf.exempt
|
||
def FilterTextV2API():
|
||
RequestedFilterText = request.form.get("text", default="", type=str)
|
||
|
||
FilteredText = FilterText(
|
||
Text = RequestedFilterText,
|
||
ReplaceWith = "#",
|
||
ThrowException = False
|
||
)
|
||
|
||
return jsonify({
|
||
"success": True,
|
||
"message": "",
|
||
"data": {
|
||
"AgeUnder13": FilteredText,
|
||
"Age13OrOver": FilteredText
|
||
}
|
||
})
|
||
|
||
@ClientInfo.route("/users/<userid>/canmanage/<placeid>", methods=['GET'])
|
||
def CanManage(userid, placeid):
|
||
AssetObj : Asset = Asset.query.filter_by(id=placeid).first()
|
||
if AssetObj is None:
|
||
return jsonify({
|
||
"CanManage": False,
|
||
"Success": True
|
||
})
|
||
if AssetObj.creator_type == 0 and AssetObj.creator_id == int(userid):
|
||
return jsonify({
|
||
"CanManage": True,
|
||
"Success": True
|
||
})
|
||
elif AssetObj.creator_type == 1:
|
||
GroupObj : Group = Group.query.filter_by(id=AssetObj.creator_id).first()
|
||
UserGroupRole : GroupRole = groups.GetUserRolesetInGroup(userid, GroupObj)
|
||
if UserGroupRole is not None:
|
||
UserRolePermissions : GroupRolePermission = groups.GetRolesetPermission( UserGroupRole )
|
||
if UserRolePermissions.manage_group_games:
|
||
return jsonify({
|
||
"CanManage": True,
|
||
"Success": True
|
||
})
|
||
return jsonify({
|
||
"CanManage": False,
|
||
"Success": True
|
||
})
|
||
|
||
@ClientInfo.route('/game/report-stats', methods=['POST'])
|
||
@csrf.exempt
|
||
def reportgamestats():
|
||
# TODO: Implement this
|
||
return jsonify({"status": "success"}),200
|
||
|
||
@ClientInfo.route("/userblock/getblockedusers", methods=['GET'])
|
||
def GetBlockedUsers():
|
||
# TODO: Implement this
|
||
return jsonify({
|
||
"success": True,
|
||
"userList": [],
|
||
"total": 0
|
||
})
|
||
|
||
@ClientInfo.route("/user/multi-following-exists", methods=['POST'])
|
||
@csrf.exempt
|
||
def MultiFollowingExists():
|
||
# TODO: Implement this
|
||
return jsonify({
|
||
"followings": [],
|
||
})
|
||
|
||
from app.util.signscript import signUTF8
|
||
@ClientInfo.route("/game/visit.ashx", methods=['GET'])
|
||
def Visit():
|
||
IsPlaySolo = request.args.get('IsPlaySolo', default=1, type=int)
|
||
UserID = request.args.get('UserID', default=5973, type=int) # default == guest
|
||
PlaceID = request.args.get('PlaceID', default=0, type=int)
|
||
UniverseId = request.args.get('UniverseId', default=0, type=int)
|
||
|
||
with open("./app/files/Visit.lua", "r") as f:
|
||
VisitLua = f.read()
|
||
VisitLua = VisitLua.format(
|
||
PlaceId = str(PlaceID),
|
||
UniverseId = str(UniverseId),
|
||
UserId = str(UserID)
|
||
)
|
||
VisitLua = signUTF8(VisitLua)
|
||
Resposne = make_response(VisitLua)
|
||
Resposne.headers['Content-Type'] = 'text/plain'
|
||
return Resposne
|
||
|
||
@ClientInfo.route("/Error/Dmp.ashx", methods=['POST'])
|
||
@csrf.exempt
|
||
def DmpAshx():
|
||
return ""
|
||
@ClientInfo.route("/Error/Grid.ashx", methods=['POST'])
|
||
@csrf.exempt
|
||
def ErrorGrid():
|
||
return "OK"
|
||
|
||
@ClientInfo.route("/game/load-place-info", methods=['GET', 'POST'])
|
||
@csrf.exempt
|
||
def load_place_info():
|
||
placeId = request.headers.get("Roblox-Place-Id", default=1, type=int)
|
||
AssetObj : Asset = Asset.query.filter_by(id=placeId).first()
|
||
if AssetObj is None:
|
||
return jsonify({
|
||
"success": False,
|
||
"message": "Place not found",
|
||
}), 404
|
||
if AssetObj.asset_type.value != 9:
|
||
return jsonify({
|
||
"success": False,
|
||
"message": "Place not found",
|
||
}), 404
|
||
LatestAssetVersion : AssetVersion = GetLatestAssetVersion(AssetObj)
|
||
return jsonify({
|
||
"CreatorId": AssetObj.creator_id,
|
||
"CreatorType": "User" if AssetObj.creator_type == 0 else "Group",
|
||
"PlaceVersion": LatestAssetVersion.version,
|
||
"GameId": placeId,
|
||
"IsRobloxPlace": True if AssetObj.creator_id == 1 and AssetObj.creator_type == 0 else False
|
||
})
|
||
|
||
@ClientInfo.route("/v1/player-policies-client", methods=["POST", "GET"])
|
||
def playerpolicies():
|
||
return jsonify({
|
||
"isSubjectToChinaPolicies":False,
|
||
"arePaidRandomItemsRestricted":False,
|
||
"isPaidItemTradingAllowed":True,
|
||
"allowedExternalLinkReferences":[
|
||
"Discord",
|
||
"YouTube",
|
||
"Twitch",
|
||
"Facebook"
|
||
]
|
||
})
|
||
|
||
EnumTogameAvatarType = {
|
||
PlaceRigChoice.UserChoice: "PlayerChoice",
|
||
PlaceRigChoice.ForceR6: "MorphToR6",
|
||
PlaceRigChoice.ForceR15: "MorphToR15"
|
||
}
|
||
|
||
@ClientInfo.route("/v1.1/game-start-info/")
|
||
def game_start_info():
|
||
universeId = request.args.get("universeId", default=None, type=int)
|
||
if universeId is None:
|
||
return jsonify({
|
||
"message": "Invalid request",
|
||
"success": False
|
||
}), 400
|
||
UniverseObj : Universe = Universe.query.filter_by(id = universeId).first()
|
||
if UniverseObj is None:
|
||
return jsonify({
|
||
"message": "Place not found",
|
||
"success": False
|
||
}), 404
|
||
|
||
return jsonify({
|
||
"gameAvatarType": "PlayerChoice", #EnumTogameAvatarType[UniverseObj.place_rig_choice], We let avatar-fetch handle this since we allow for place specific avatar types
|
||
"allowCustomAnimations":"True",
|
||
"universeAvatarCollisionType":"OuterBox",
|
||
"universeAvatarBodyType":"Standard",
|
||
"jointPositioningType":"ArtistIntent",
|
||
"message":"",
|
||
"universeAvatarMinScales":{
|
||
"height":0.9,
|
||
"width":0.7,
|
||
"head":0.95,
|
||
"depth":0.0,
|
||
"proportion":0.0,
|
||
"bodyType":0.0
|
||
},
|
||
"universeAvatarMaxScales":{
|
||
"height":1.05,
|
||
"width":1.0,
|
||
"head":1.0,
|
||
"depth":0.0,
|
||
"proportion":1.0,
|
||
"bodyType":1.0
|
||
},
|
||
"universeAvatarAssetOverrides":[],
|
||
"moderationStatus":None
|
||
})
|
||
|
||
@ClientInfo.route("/v1/name-description/games/<int:placeid>", methods=["GET"])
|
||
def name_description(placeid):
|
||
PlaceObj : Place = Place.query.filter_by(placeid=placeid).first()
|
||
if PlaceObj is None:
|
||
return jsonify({
|
||
"message": "Place not found",
|
||
"success": False
|
||
}), 404
|
||
AssetObj : Asset = PlaceObj.assetObj
|
||
return jsonify({
|
||
"data":[
|
||
{
|
||
"name":AssetObj.name,
|
||
"description":AssetObj.description,
|
||
"languageCode":"en"
|
||
}
|
||
]
|
||
})
|
||
|
||
@ClientInfo.route("/v1/locales", methods=["GET"])
|
||
def client_locales():
|
||
return jsonify({"data":[{"locale":{"id":1,"locale":"en_us","name":"English(US)","nativeName":"English","language":{"id":41,"name":"English","nativeName":"English","languageCode":"en"}},"isEnabledForFullExperience":True,"isEnabledForSignupAndLogin":True,"isEnabledForInGameUgc":True},{"locale":{"id":2,"locale":"es_es","name":"Spanish(Spain)","nativeName":"Español","language":{"id":148,"name":"Spanish","nativeName":"Español","languageCode":"es"}},"isEnabledForFullExperience":True,"isEnabledForSignupAndLogin":True,"isEnabledForInGameUgc":True},{"locale":{"id":3,"locale":"fr_fr","name":"French","nativeName":"Français","language":{"id":48,"name":"French","nativeName":"Français","languageCode":"fr"}},"isEnabledForFullExperience":True,"isEnabledForSignupAndLogin":True,"isEnabledForInGameUgc":True},{"locale":{"id":4,"locale":"id_id","name":"Indonesian","nativeName":"Bahasa Indonesia","language":{"id":64,"name":"Indonesian","nativeName":"Bahasa Indonesia","languageCode":"id"}},"isEnabledForFullExperience":False,"isEnabledForSignupAndLogin":False,"isEnabledForInGameUgc":True},{"locale":{"id":5,"locale":"it_it","name":"Italian","nativeName":"Italiano","language":{"id":71,"name":"Italian","nativeName":"Italiano","languageCode":"it"}},"isEnabledForFullExperience":False,"isEnabledForSignupAndLogin":False,"isEnabledForInGameUgc":True},{"locale":{"id":6,"locale":"ja_jp","name":"Japanese","nativeName":"日本語","language":{"id":73,"name":"Japanese","nativeName":"日本語 (にほんご),","languageCode":"ja"}},"isEnabledForFullExperience":True,"isEnabledForSignupAndLogin":True,"isEnabledForInGameUgc":True},{"locale":{"id":7,"locale":"ko_kr","name":"Korean","nativeName":"한국어","language":{"id":86,"name":"Korean","nativeName":"한국어","languageCode":"ko"}},"isEnabledForFullExperience":True,"isEnabledForSignupAndLogin":True,"isEnabledForInGameUgc":True},{"locale":{"id":8,"locale":"ru_ru","name":"Russian","nativeName":"Русский","language":{"id":133,"name":"Russian","nativeName":"Русский","languageCode":"ru"}},"isEnabledForFullExperience":False,"isEnabledForSignupAndLogin":False,"isEnabledForInGameUgc":True},{"locale":{"id":9,"locale":"th_th","name":"Thai","nativeName":"ภาษาไทย","language":{"id":156,"name":"Thai","nativeName":"ไทย","languageCode":"th"}},"isEnabledForFullExperience":False,"isEnabledForSignupAndLogin":False,"isEnabledForInGameUgc":True},{"locale":{"id":10,"locale":"tr_tr","name":"Turkish","nativeName":"Türkçe","language":{"id":163,"name":"Turkish","nativeName":"Türkçe","languageCode":"tr"}},"isEnabledForFullExperience":False,"isEnabledForSignupAndLogin":False,"isEnabledForInGameUgc":True},{"locale":{"id":11,"locale":"vi_vn","name":"Vietnamese","nativeName":"Tiếng Việt","language":{"id":173,"name":"Vietnamese","nativeName":"Tiếng Việt","languageCode":"vi"}},"isEnabledForFullExperience":False,"isEnabledForSignupAndLogin":False,"isEnabledForInGameUgc":True},{"locale":{"id":12,"locale":"pt_br","name":"Portuguese (Brazil)","nativeName":"Português (Brasil)","language":{"id":128,"name":"Portuguese","nativeName":"Português","languageCode":"pt"}},"isEnabledForFullExperience":True,"isEnabledForSignupAndLogin":True,"isEnabledForInGameUgc":True},{"locale":{"id":13,"locale":"de_de","name":"German","nativeName":"Deutsch","language":{"id":52,"name":"German","nativeName":"Deutsch","languageCode":"de"}},"isEnabledForFullExperience":True,"isEnabledForSignupAndLogin":True,"isEnabledForInGameUgc":True},{"locale":{"id":14,"locale":"zh_cn","name":"Chinese (Simplified)","nativeName":"中文(简体)","language":{"id":30,"name":"Chinese (Simplified)","nativeName":"简体中文","languageCode":"zh-hans"}},"isEnabledForFullExperience":True,"isEnabledForSignupAndLogin":True,"isEnabledForInGameUgc":True},{"locale":{"id":15,"locale":"zh_tw","name":"Chinese (Traditional)","nativeName":"中文(繁體)","language":{"id":189,"name":"Chinese (Traditional)","nativeName":"繁體中文","languageCode":"zh-hant"}},"isEnabledForFullExperience":True,"isEnabledForSignupAndLogin":True,"isEnabledForInGameUgc":True},{"locale":{"id":16,"locale":"bg_bg","name":"Bulgarian","nativeName":"Български","language":{"id":24,"name":"Bulgarian","nativeName":"български език","languageCode":"bg"}},"isEnabledForFullExperience":False,"isEnabledForSignupAndLogin":False,"isEnabledForInGameUgc":True},{"locale":{"id":17,"locale":"bn_bd","name":"Bengali","nativeName":"বাংলা","language":{"id":19,"name":"Bengali","nativeName":"বাংলা","languageCode":"bn"}},"isEnabledForFullExperience":False,"isEnabledForSignupAndLogin":False,"isEnabledForInGameUgc":True},{"locale":{"id":18,"locale":"cs_cz","name":"Czech","nativeName":"Čeština","language":{"id":36,"name":"Czech","nativeName":"čeština","languageCode":"cs"}},"isEnabledForFullExperience":False,"isEnabledForSignupAndLogin":False,"isEnabledForInGameUgc":True},{"locale":{"id":19,"locale":"da_dk","name":"Danish","nativeName":"Dansk","language":{"id":37,"name":"Danish","nativeName":"dansk","languageCode":"da"}},"isEnabledForFullExperience":False,"isEnabledForSignupAndLogin":False,"isEnabledForInGameUgc":True},{"locale":{"id":20,"locale":"el_gr","name":"Greek","nativeName":"Ελληνικά","language":{"id":53,"name":"Greek","nativeName":"ελληνικά","languageCode":"el"}},"isEnabledForFullExperience":False,"isEnabledForSignupAndLogin":False,"isEnabledForInGameUgc":True},{"locale":{"id":21,"locale":"et_ee","name":"Estonian","nativeName":"Eesti","language":{"id":43,"name":"Estonian","nativeName":"eesti, eesti keel","languageCode":"et"}},"isEnabledForFullExperience":False,"isEnabledForSignupAndLogin":False,"isEnabledForInGameUgc":True},{"locale":{"id":22,"locale":"fi_fi","name":"Finnish","nativeName":"Suomi","language":{"id":47,"name":"Finnish","nativeName":"suomi","languageCode":"fi"}},"isEnabledForFullExperience":False,"isEnabledForSignupAndLogin":False,"isEnabledForInGameUgc":True},{"locale":{"id":23,"locale":"hi_in","name":"Hindi","nativeName":"हिन्दी","language":{"id":60,"name":"Hindi","nativeName":"हिन्दी, हिंदी","languageCode":"hi"}},"isEnabledForFullExperience":False,"isEnabledForSignupAndLogin":False,"isEnabledForInGameUgc":True},{"locale":{"id":24,"locale":"hr_hr","name":"Croatian","nativeName":"Hrvatski","language":{"id":35,"name":"Croatian","nativeName":"hrvatski jezik","languageCode":"hr"}},"isEnabledForFullExperience":False,"isEnabledForSignupAndLogin":False,"isEnabledForInGameUgc":True},{"locale":{"id":25,"locale":"hu_hu","name":"Hungarian","nativeName":"Magyar","language":{"id":62,"name":"Hungarian","nativeName":"magyar","languageCode":"hu"}},"isEnabledForFullExperience":False,"isEnabledForSignupAndLogin":False,"isEnabledForInGameUgc":True},{"locale":{"id":26,"locale":"ka_ge","name":"Georgian","nativeName":"ქართული","language":{"id":51,"name":"Georgian","nativeName":"ქართული","languageCode":"ka"}},"isEnabledForFullExperience":False,"isEnabledForSignupAndLogin":False,"isEnabledForInGameUgc":True},{"locale":{"id":27,"locale":"kk_kz","name":"Kazakh","nativeName":"Қазақ Тілі","language":{"id":79,"name":"Kazakh","nativeName":"қазақ тілі","languageCode":"kk"}},"isEnabledForFullExperience":False,"isEnabledForSignupAndLogin":False,"isEnabledForInGameUgc":True},{"locale":{"id":28,"locale":"km_kh","name":"Khmer","nativeName":"ភាសាខ្មែរ","language":{"id":188,"name":"Khmer","nativeName":"ភាសាខ្មែរ","languageCode":"km"}},"isEnabledForFullExperience":False,"isEnabledForSignupAndLogin":False,"isEnabledForInGameUgc":True},{"locale":{"id":29,"locale":"lt_lt","name":"Lithuanian","nativeName":"Lietuvių","language":{"id":95,"name":"Lithuanian","nativeName":"lietuvių kalba","languageCode":"lt"}},"isEnabledForFullExperience":False,"isEnabledForSignupAndLogin":False,"isEnabledForInGameUgc":True},{"locale":{"id":30,"locale":"lv_lv","name":"Latvian","nativeName":"Latviešu","language":{"id":97,"name":"Latvian","nativeName":"Latviešu Valoda","languageCode":"lv"}},"isEnabledForFullExperience":False,"isEnabledForSignupAndLogin":False,"isEnabledForInGameUgc":True},{"locale":{"id":31,"locale":"ms_my","name":"Malay","nativeName":"Bahasa Melayu","language":{"id":101,"name":"Malay","nativeName":"بهاس ملايو","languageCode":"ms"}},"isEnabledForFullExperience":False,"isEnabledForSignupAndLogin":False,"isEnabledForInGameUgc":True},{"locale":{"id":32,"locale":"my_mm","name":"Burmese","nativeName":"ဗမာစာ","language":{"id":25,"name":"Burmese","nativeName":"ဗမာစာ","languageCode":"my"}},"isEnabledForFullExperience":False,"isEnabledForSignupAndLogin":False,"isEnabledForInGameUgc":True},{"locale":{"id":33,"locale":"nb_no","name":"Bokmal","nativeName":"Bokmål","language":{"id":113,"name":"Bokmal","nativeName":"Norsk Bokmål","languageCode":"nb"}},"isEnabledForFullExperience":False,"isEnabledForSignupAndLogin":False,"isEnabledForInGameUgc":True},{"locale":{"id":34,"locale":"nl_nl","name":"Dutch","nativeName":"Nederlands","language":{"id":39,"name":"Dutch","nativeName":"Nederlands","languageCode":"nl"}},"isEnabledForFullExperience":False,"isEnabledForSignupAndLogin":False,"isEnabledForInGameUgc":True},{"locale":{"id":35,"locale":"fil_ph","name":"Filipino","nativeName":"Filipino","language":{"id":190,"name":"Filipino","nativeName":"Filipino","languageCode":"fil"}},"isEnabledForFullExperience":False,"isEnabledForSignupAndLogin":False,"isEnabledForInGameUgc":True},{"locale":{"id":36,"locale":"pl_pl","name":"Polish","nativeName":"Polski","language":{"id":126,"name":"Polish","nativeName":"Język Polski","languageCode":"pl"}},"isEnabledForFullExperience":False,"isEnabledForSignupAndLogin":False,"isEnabledForInGameUgc":True},{"locale":{"id":37,"locale":"ro_ro","name":"Romanian","nativeName":"Română","language":{"id":132,"name":"Romanian","nativeName":"Română","languageCode":"ro"}},"isEnabledForFullExperience":False,"isEnabledForSignupAndLogin":False,"isEnabledForInGameUgc":True},{"locale":{"id":38,"locale":"uk_ua","name":"Ukrainian","nativeName":"Yкраїньска","language":{"id":169,"name":"Ukrainian","nativeName":"Українська","languageCode":"uk"}},"isEnabledForFullExperience":False,"isEnabledForSignupAndLogin":False,"isEnabledForInGameUgc":True},{"locale":{"id":39,"locale":"si_lk","name":"Sinhala","nativeName":"සිංහල","language":{"id":143,"name":"Sinhala","nativeName":"සිංහල","languageCode":"si"}},"isEnabledForFullExperience":False,"isEnabledForSignupAndLogin":False,"isEnabledForInGameUgc":True},{"locale":{"id":40,"locale":"sk_sk","name":"Slovak","nativeName":"Slovenčina","language":{"id":144,"name":"Slovak","nativeName":"Slovenčina","languageCode":"sk"}},"isEnabledForFullExperience":False,"isEnabledForSignupAndLogin":False,"isEnabledForInGameUgc":True},{"locale":{"id":41,"locale":"sl_sl","name":"Slovenian","nativeName":"Slovenski","language":{"id":145,"name":"Slovenian","nativeName":"Slovenščina","languageCode":"sl"}},"isEnabledForFullExperience":False,"isEnabledForSignupAndLogin":False,"isEnabledForInGameUgc":True},{"locale":{"id":42,"locale":"sq_al","name":"Albanian","nativeName":"Shqipe","language":{"id":5,"name":"Albanian","nativeName":"Shqip","languageCode":"sq"}},"isEnabledForFullExperience":False,"isEnabledForSignupAndLogin":False,"isEnabledForInGameUgc":True},{"locale":{"id":43,"locale":"bs_ba","name":"Bosnian","nativeName":"Босански","language":{"id":22,"name":"Bosnian","nativeName":"bosanski jezik","languageCode":"bs"}},"isEnabledForFullExperience":False,"isEnabledForSignupAndLogin":False,"isEnabledForInGameUgc":True},{"locale":{"id":44,"locale":"sr_rs","name":"Serbian","nativeName":"Cрпски","language":{"id":140,"name":"Serbian","nativeName":"српски језик","languageCode":"sr"}},"isEnabledForFullExperience":False,"isEnabledForSignupAndLogin":False,"isEnabledForInGameUgc":True},{"locale":{"id":45,"locale":"sv_se","name":"Swedish","nativeName":"Svenska","language":{"id":152,"name":"Swedish","nativeName":"Svenska","languageCode":"sv"}},"isEnabledForFullExperience":False,"isEnabledForSignupAndLogin":False,"isEnabledForInGameUgc":True}]})
|
||
|
||
@ClientInfo.route("/v2/universes/<int:universeid>/configuration", methods=["GET"])
|
||
def GetUniverseConfig( universeid : int ):
|
||
return jsonify({
|
||
"allowPrivateServers": False,
|
||
"privateServerPrice": 0,
|
||
"id": universeid,
|
||
"name": "MrGrey",
|
||
"universeAvatarType": "PlayerChoice",
|
||
"universeScaleType": "AllScales",
|
||
"universeAnimationType": "PlayerChoice",
|
||
"universeCollisionType": "OuterBox",
|
||
"universeBodyType": "Standard",
|
||
"universeJointPositioningType": "ArtistIntent",
|
||
"isArchived": False,
|
||
"isFriendsOnly": False,
|
||
"genre": "All",
|
||
"playableDevices": [
|
||
"Computer",
|
||
"Phone",
|
||
"Tablet"
|
||
],
|
||
"permissions": {
|
||
"IsThirdPartyTeleportAllowed": True,
|
||
"IsThirdPartyAssetAllowed": True,
|
||
"IsThirdPartyPurchaseAllowed": True
|
||
},
|
||
"isForSale": False,
|
||
"price": 0,
|
||
"isStudioAccessToApisAllowed": True,
|
||
"privacyType": "Private"
|
||
})
|
||
|
||
@ClientInfo.route("/universal-app-configuration/v1/behaviors/app-patch/content", methods=["GET"])
|
||
def GetAppConfigContent():
|
||
return jsonify({
|
||
"SchemaVersion": "1",
|
||
"CanaryUserIds": [],
|
||
"CanaryPercentage": 0
|
||
})
|
||
|
||
@ClientInfo.route("/debu-client/im-person-ate", methods=["POST"])
|
||
@csrf.exempt
|
||
def im_person_ate():
|
||
try:
|
||
if not config.DEBUG_MODE:
|
||
return abort(404)
|
||
except:
|
||
pass
|
||
|
||
if not request.is_json:
|
||
return abort(404)
|
||
data = request.json
|
||
|
||
try:
|
||
assert "userId" in data, "userId not found"
|
||
assert isinstance(data["userId"], int), "userId is not an integer"
|
||
except AssertionError as e:
|
||
return f"Validation failed: {str(e)}", 400
|
||
|
||
req_response = make_response("OK", 200)
|
||
req_response.headers["ImpData"] = auth.CreateToken( userid = data["userId"], expireIn = 60 * 60 * 24 * 365 )
|
||
return req_response
|
||
|
||
|
||
@ClientInfo.route("/universal-app-configuration/v1/behaviors/app-policy/content", methods=["GET"])
|
||
def GetAppPolicyContent():
|
||
return jsonify({
|
||
"ChatConversationHeaderGroupDetails": True,
|
||
"ChatHeaderSearch": True,
|
||
"ChatHeaderCreateChatGroup": True,
|
||
"ChatHeaderHomeButton": False,
|
||
"ChatHeaderNotifications": True,
|
||
"ChatPlayTogether": True,
|
||
"ChatShareGameToChatFromChat": True,
|
||
"ChatTapConversationThumbnail": True,
|
||
"ChatViewProfileOption": True,
|
||
"GamesDropDownList": True,
|
||
"UseNewDropDown": False,
|
||
"GameDetailsMorePage": True,
|
||
"GameDetailsShowGlobalCounters": True,
|
||
"GameDetailsPlayWithFriends": True,
|
||
"GameDetailsSubtitle": True,
|
||
"GameInfoList": True,
|
||
"GameInfoListDeveloper": True,
|
||
"GamePlaysAndRatings": True,
|
||
"GameInfoShowBadges": True,
|
||
"GameInfoShowCreated": True,
|
||
"GameInfoShowGamepasses": True,
|
||
"GameInfoShowGenre": True,
|
||
"GameInfoShowMaxPlayers": True,
|
||
"GameInfoShowServers": True,
|
||
"GameInfoShowUpdated": True,
|
||
"GameReportingDisabled": False,
|
||
"GamePlayerCounts": True,
|
||
"GiftCardsEnabled": False,
|
||
"Notifications": True,
|
||
"OfficialStoreEnabled": False,
|
||
"RecommendedGames": True,
|
||
"SearchBar": True,
|
||
"MorePageType": "More",
|
||
"AboutPageType": "About",
|
||
"FriendFinder": True,
|
||
"SocialLinks": True,
|
||
"SocialGroupLinks": True,
|
||
"EnableShareCaptureCTA": True,
|
||
"SiteMessageBanner": True,
|
||
"UseWidthBasedFormFactorRule": False,
|
||
"UseHomePageWithAvatarAndPanel": False,
|
||
"UseBottomBar": True,
|
||
"AvatarHeaderIcon": "LuaApp/icons/ic-back",
|
||
"AvatarEditorShowBuyRobuxOnTopBar": True,
|
||
"HomeIcon": "LuaApp/icons/ic-roblox-close",
|
||
"ShowYouTubeAgeAlert": False,
|
||
"GameDetailsShareButton": True,
|
||
"CatalogShareButton": True,
|
||
"AccountProviderName": "",
|
||
"InviteFromAccountProvider": False,
|
||
"ShareToAccountProvider": False,
|
||
"ShareToAccountProviderTimeout": 8,
|
||
"ShowDisplayName": True,
|
||
"GamesPageCreationCenterTitle": False,
|
||
"ShowShareTargetGameCreator": True,
|
||
"SearchAutoComplete": True,
|
||
"CatalogShow3dView": True,
|
||
"CatalogReportingDisabled": False,
|
||
"CatalogCommunityCreations": True,
|
||
"CatalogPremiumCategory": True,
|
||
"CatalogPremiumContent": True,
|
||
"ItemDetailsFullView": True,
|
||
"UseAvatarExperienceLandingPage": True,
|
||
"HomePageFriendSection": True,
|
||
"HomePageProfileLink": True,
|
||
"PurchasePromptIncludingWarning": False,
|
||
"ShowVideoThumbnails": True,
|
||
"VideoSharingTestContent": [],
|
||
"SystemBarPlacement": "Bottom",
|
||
"EnableInGameHomeIcon": False,
|
||
"UseExternalBrowserForDisclaimerLinks": False,
|
||
"ShowExitFullscreenToast": True,
|
||
"ExitFullscreenToastEnabled": False,
|
||
"UseLuobuAuthentication": False,
|
||
"CheckUserAgreementsUpdatedOnLogin": True,
|
||
"AddUserAgreementIdsToSignupRequest": True,
|
||
"UseOmniRecommendation": True,
|
||
"ShowAgeVerificationOverlayEnabled": False,
|
||
"ShouldShowGroupsTile": True,
|
||
"ShowVoiceUpsell": False,
|
||
"ProfileShareEnabled": True,
|
||
"ContactImporterEnabled": True,
|
||
"FriendCodeQrCodeScannerEnabled": False,
|
||
"RealNamesInDisplayNamesEnabled": False,
|
||
"CsatSurveyRestrictTextInput": False,
|
||
"RobloxCreatedItemsCreatedByLuobu": False,
|
||
"GameInfoShowChatFeatures": True,
|
||
"PlatformGroup": "Unknown",
|
||
"UsePhoneSearchDiscoverEntry": False,
|
||
"HomeLocalFeedItems": {
|
||
"UserInfo": 1,
|
||
"FriendCarousel": 2
|
||
},
|
||
"Routes": {
|
||
"auth": {
|
||
"connect": "v2/login",
|
||
"login": "v2/login",
|
||
"signup": "v2/signup"
|
||
}
|
||
},
|
||
"PromotionalEmailsCheckboxEnabled": True,
|
||
"PromotionalEmailsOptInByDefault": False,
|
||
"EnablePremiumUserFeatures": True,
|
||
"CanShowUnifiedChatUpsell": True,
|
||
"RequireExplicitVoiceConsent": True,
|
||
"RequireExplicitAvatarVideoConsent": True,
|
||
"EnableVoiceReportAbuseMenu": True
|
||
})
|
||
|
||
@ClientInfo.route("/game/studio.ashx", methods=['GET'])
|
||
def studio():
|
||
StudioLua = open("./app/files/Studio.lua", "r").read()
|
||
SignedStudioLua = signUTF8(StudioLua)
|
||
Response = make_response(SignedStudioLua)
|
||
Response.headers['Content-Type'] = 'text/plain'
|
||
return Response
|
||
|
||
@ClientInfo.route("/game/gameserver2014.lua", methods=['GET'])
|
||
def gameserver_2014():
|
||
RemoteAddress = get_remote_address()
|
||
GameserverObj : GameServer = GameServer.query.filter_by( serverIP = RemoteAddress ).first()
|
||
if GameserverObj is None:
|
||
return jsonify({
|
||
"success": False,
|
||
"message": "Unauthorized"
|
||
}), 401
|
||
|
||
PlaceId = request.args.get( key = "placeId", default = None, type = int )
|
||
NetworkPort = request.args.get( key = "networkPort", default = None, type = int )
|
||
CreatorId = request.args.get( key = "creatorId", default = None, type = int )
|
||
CreatorType = request.args.get( key = "creatorType", default = None, type = int )
|
||
JobId = request.args.get( key = "jobId", default = None, type = str )
|
||
|
||
if "UserRequest" in request.headers.get( key = "accesskey", default = "" ):
|
||
return jsonify({
|
||
"success": False,
|
||
"message": "Invalid request"
|
||
}), 400
|
||
|
||
if PlaceId is None or NetworkPort is None or CreatorId is None or CreatorType is None or JobId is None:
|
||
return jsonify({
|
||
"success": False,
|
||
"message": "Invalid request"
|
||
}), 400
|
||
|
||
PlaceObj : Place = Place.query.filter_by(placeid=PlaceId).first()
|
||
if PlaceObj is None:
|
||
return jsonify({
|
||
"success": False,
|
||
"message": "Place not found"
|
||
}), 404
|
||
|
||
UniverseObj : Universe = Universe.query.filter_by(id=PlaceObj.parent_universe_id).first()
|
||
if UniverseObj is None:
|
||
return jsonify({
|
||
"success": False,
|
||
"message": "Universe not found"
|
||
}), 404
|
||
|
||
if UniverseObj.place_year != PlaceYear.Fourteen:
|
||
return jsonify({
|
||
"success": False,
|
||
"message": "Invalid request"
|
||
}), 400
|
||
|
||
#if not redis_controller.exists(f"gameserver2014lua:{PlaceId}:{JobId}"):
|
||
# return jsonify({
|
||
# "success": False,
|
||
# "message": "Invalid request"
|
||
# }), 400
|
||
#redis_controller.delete(f"gameserver2014lua:{PlaceId}:{JobId}")
|
||
|
||
TempPlaceAccessKey = GenerateTempAuthToken(
|
||
AssetId = PlaceId,
|
||
Expiration = 180,
|
||
CreatorIP = get_remote_address()
|
||
)
|
||
GameserverLua = open("./app/files/2014Gameserver.lua", "r").read()
|
||
GameserverLua = GameserverLua.format(
|
||
PlaceId = PlaceId,
|
||
NetworkPort = NetworkPort,
|
||
CreatorId = CreatorId,
|
||
CreatorType = CreatorType,
|
||
JobId = JobId,
|
||
AuthToken = GameserverObj.accessKey,
|
||
TempPlaceAccessKey = TempPlaceAccessKey
|
||
)
|
||
|
||
SignedGameserverLua = signUTF8(GameserverLua)
|
||
Response = make_response(SignedGameserverLua)
|
||
Response.headers['Content-Type'] = 'text/plain'
|
||
Response.set_cookie(
|
||
key = "Roblox-Place-Id",
|
||
value = str(PlaceId),
|
||
expires = 60 * 60 * 24,
|
||
domain = f".{config.BaseDomain}"
|
||
)
|
||
Response.set_cookie(
|
||
key = "Temp-Place-Access-Key",
|
||
value = TempPlaceAccessKey,
|
||
expires = 180,
|
||
domain = f".{config.BaseDomain}"
|
||
)
|
||
|
||
logging.info("2014Gameserver.lua request from %s for place %d", RemoteAddress, PlaceId)
|
||
|
||
return Response
|
||
|
||
@ClientInfo.route("/game/gameserver2016.lua", methods=['GET'])
|
||
def gameserver_2016():
|
||
RemoteAddress = get_remote_address()
|
||
GameserverObj : GameServer = GameServer.query.filter_by( serverIP = RemoteAddress ).first()
|
||
if GameserverObj is None:
|
||
return jsonify({
|
||
"success": False,
|
||
"message": "Unauthorized"
|
||
}), 401
|
||
|
||
GameserverLua = open("./app/files/2016Gameserver.lua", "r").read()
|
||
GameserverLua = f"-- Syntax 2016 Gameserver.lua | Signed on {datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n" + GameserverLua
|
||
|
||
SignedGameserverLua = signUTF8(GameserverLua)
|
||
Response = make_response(SignedGameserverLua)
|
||
Response.headers['Content-Type'] = 'text/plain'
|
||
|
||
logging.info("2016Gameserver.lua request from %s", RemoteAddress)
|
||
|
||
return Response
|
||
|
||
@ClientInfo.route("/game/2014Join.lua", methods=['GET'])
|
||
def join_2014():
|
||
placeId = request.args.get("placeId", default=None, type=int)
|
||
if placeId is None:
|
||
return jsonify({
|
||
"success": False,
|
||
"message": "Invalid request"
|
||
}), 400
|
||
|
||
JoinLua = open("./app/files/2014Join.lua", "r").read()
|
||
JoinLua = JoinLua.format(
|
||
PlaceId = str(placeId)
|
||
)
|
||
SignedJoinLua = signUTF8(JoinLua)
|
||
Response = make_response(SignedJoinLua)
|
||
Response.headers['Content-Type'] = 'text/plain'
|
||
return Response
|
||
|
||
@ClientInfo.route("/v1/users/<int:userId>/currency", methods=["GET"])
|
||
@auth.authenticated_required_api
|
||
def get_user_currency( userId : int ):
|
||
AuthenticatedUser : User = auth.GetCurrentUser()
|
||
if AuthenticatedUser.id != userId:
|
||
return jsonify({"success": False, "message": "Unauthorized"}),401
|
||
UserRobuxBalance, UserTixBalance = economy.GetUserBalance(AuthenticatedUser)
|
||
return jsonify({
|
||
"robux": UserRobuxBalance,
|
||
"tickets": UserTixBalance
|
||
}),200
|
||
|
||
#followings.roblox.com/v1/users/<int:userid>/universes/<int:universeid>/status
|
||
@ClientInfo.route("/v1/users/<int:userid>/universes/<int:universeid>/status", methods=["GET"])
|
||
@auth.authenticated_required_api
|
||
def get_user_following_universe_status( userid : int, universeid : int ):
|
||
AuthenticatedUser : User = auth.GetCurrentUser()
|
||
if AuthenticatedUser.id != userid:
|
||
return jsonify({"success": False, "message": "Unauthorized"}),401
|
||
return jsonify({
|
||
"UniverseId": universeid,
|
||
"UserId": userid,
|
||
"CanFollow": False,
|
||
"IsFollowing": False,
|
||
"FollowingCountByType": 0,
|
||
"FollowingLimitByType": 200
|
||
}),200
|
||
|
||
#badges.roblox.com/v1/universes/<int:universeid>/badges
|
||
@ClientInfo.route("/v1/universes/<int:universeid>/badges", methods=["GET"])
|
||
@auth.authenticated_required_api
|
||
def get_universe_badges( universeid : int ):
|
||
return jsonify({
|
||
"data": [],
|
||
"previousPageCursor": None,
|
||
"nextPageCursor": None
|
||
}),200
|