mirror of
https://github.com/derrod/legendary.git
synced 2024-12-22 17:55:27 +00:00
[api/core/models] Add support for "Ownership Token"
Ownership verification tokens appear to be part of EPIC's DRM scheme, they're basically just a JSON file with a token in it that's downloaded from their API before launching. This fixes launching games such as Just Cause 4.
This commit is contained in:
parent
ce28ce2914
commit
5eb51dfd11
|
@ -19,6 +19,7 @@ class EPCAPI:
|
||||||
_launcher_host = 'launcher-public-service-prod06.ol.epicgames.com'
|
_launcher_host = 'launcher-public-service-prod06.ol.epicgames.com'
|
||||||
_entitlements_host = 'entitlement-public-service-prod08.ol.epicgames.com'
|
_entitlements_host = 'entitlement-public-service-prod08.ol.epicgames.com'
|
||||||
_catalog_host = 'catalog-public-service-prod06.ol.epicgames.com'
|
_catalog_host = 'catalog-public-service-prod06.ol.epicgames.com'
|
||||||
|
_ecommerce_host = 'ecommerceintegration-public-service-ecomprod02.ol.epicgames.com'
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.session = requests.session()
|
self.session = requests.session()
|
||||||
|
@ -71,6 +72,14 @@ class EPCAPI:
|
||||||
r.raise_for_status()
|
r.raise_for_status()
|
||||||
return r.json()
|
return r.json()
|
||||||
|
|
||||||
|
def get_ownership_token(self, namespace, catalog_item_id):
|
||||||
|
user_id = self.user.get('account_id')
|
||||||
|
r = self.session.post(f'https://{self._ecommerce_host}/ecommerceintegration/api/public/'
|
||||||
|
f'platforms/EPIC/identities/{user_id}/ownershipToken',
|
||||||
|
data=dict(nsCatalogItemId=f'{namespace}:{catalog_item_id}'))
|
||||||
|
r.raise_for_status()
|
||||||
|
return r.content
|
||||||
|
|
||||||
def get_game_assets(self):
|
def get_game_assets(self):
|
||||||
r = self.session.get(f'https://{self._launcher_host}/launcher/api/public/assets/Windows',
|
r = self.session.get(f'https://{self._launcher_host}/launcher/api/public/assets/Windows',
|
||||||
params=dict(label='Live'))
|
params=dict(label='Live'))
|
||||||
|
|
|
@ -320,5 +320,5 @@ def main():
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
multiprocessing.freeze_support()
|
multiprocessing.freeze_support() # required for pyinstaller
|
||||||
main()
|
main()
|
||||||
|
|
|
@ -162,11 +162,14 @@ class LegendaryCore:
|
||||||
def get_launch_parameters(self, app_name: str, offline: bool = False,
|
def get_launch_parameters(self, app_name: str, offline: bool = False,
|
||||||
user: str = None, extra_args: list = None) -> (list, str, dict):
|
user: str = None, extra_args: list = None) -> (list, str, dict):
|
||||||
install = self.lgd.get_installed_game(app_name)
|
install = self.lgd.get_installed_game(app_name)
|
||||||
|
game = self.lgd.get_game_meta(app_name)
|
||||||
|
|
||||||
game_token = ''
|
game_token = ''
|
||||||
if not offline:
|
if not offline:
|
||||||
self.log.info('Getting authentication token...')
|
self.log.info('Getting authentication token...')
|
||||||
game_token = self.egs.get_game_token()['code']
|
game_token = self.egs.get_game_token()['code']
|
||||||
|
elif not install.can_run_offline:
|
||||||
|
self.log.warning('Game is not approved for offline use and may not work correctly.')
|
||||||
|
|
||||||
user_name = self.lgd.userdata['displayName']
|
user_name = self.lgd.userdata['displayName']
|
||||||
account_id = self.lgd.userdata['account_id']
|
account_id = self.lgd.userdata['account_id']
|
||||||
|
@ -191,7 +194,19 @@ class LegendaryCore:
|
||||||
f'-AUTH_PASSWORD={game_token}',
|
f'-AUTH_PASSWORD={game_token}',
|
||||||
'-AUTH_TYPE=exchangecode',
|
'-AUTH_TYPE=exchangecode',
|
||||||
f'-epicapp={app_name}',
|
f'-epicapp={app_name}',
|
||||||
'-epicenv=Prod',
|
'-epicenv=Prod'])
|
||||||
|
|
||||||
|
if install.requires_ot and not offline:
|
||||||
|
self.log.info('Getting ownership token.')
|
||||||
|
ovt = self.egs.get_ownership_token(game.asset_info.namespace,
|
||||||
|
game.asset_info.catalog_item_id)
|
||||||
|
ovt_path = os.path.join(self.lgd.get_tmp_path(),
|
||||||
|
f'{game.asset_info.namespace}{game.asset_info.catalog_item_id}.ovt')
|
||||||
|
with open(ovt_path, 'wb') as f:
|
||||||
|
f.write(ovt)
|
||||||
|
params.append(f'-epicovt={ovt_path}')
|
||||||
|
|
||||||
|
params.extend([
|
||||||
'-EpicPortal',
|
'-EpicPortal',
|
||||||
f'-epicusername={user_name}',
|
f'-epicusername={user_name}',
|
||||||
f'-epicuserid={account_id}',
|
f'-epicuserid={account_id}',
|
||||||
|
@ -333,10 +348,14 @@ class LegendaryCore:
|
||||||
prereq = dict(ids=new_manifest.meta.prereq_ids, name=new_manifest.meta.prereq_name,
|
prereq = dict(ids=new_manifest.meta.prereq_ids, name=new_manifest.meta.prereq_name,
|
||||||
path=new_manifest.meta.prereq_path, args=new_manifest.meta.prereq_args)
|
path=new_manifest.meta.prereq_path, args=new_manifest.meta.prereq_args)
|
||||||
|
|
||||||
|
offline = game.metadata.get('customAttributes', {}).get('CanRunOffline', {}).get('value', 'true')
|
||||||
|
ot = game.metadata.get('customAttributes', {}).get('OwnershipToken', {}).get('value', 'false')
|
||||||
|
|
||||||
igame = InstalledGame(app_name=game.app_name, title=game.app_title, version=game.app_version,
|
igame = InstalledGame(app_name=game.app_name, title=game.app_title, version=game.app_version,
|
||||||
prereq_info=prereq, manifest_path=override_manifest, base_urls=base_urls,
|
prereq_info=prereq, manifest_path=override_manifest, base_urls=base_urls,
|
||||||
install_path=install_path, executable=new_manifest.meta.launch_exe,
|
install_path=install_path, executable=new_manifest.meta.launch_exe,
|
||||||
launch_parameters=new_manifest.meta.launch_command)
|
launch_parameters=new_manifest.meta.launch_command,
|
||||||
|
can_run_offline=offline == 'true', requires_ot=ot == 'true')
|
||||||
|
|
||||||
return dlm, anlres, igame
|
return dlm, anlres, igame
|
||||||
|
|
||||||
|
|
|
@ -68,7 +68,8 @@ class Game:
|
||||||
|
|
||||||
class InstalledGame:
|
class InstalledGame:
|
||||||
def __init__(self, app_name='', title='', version='', manifest_path='', base_urls=None,
|
def __init__(self, app_name='', title='', version='', manifest_path='', base_urls=None,
|
||||||
install_path='', executable='', launch_parameters='', prereq_info=None):
|
install_path='', executable='', launch_parameters='', prereq_info=None,
|
||||||
|
can_run_offline=False, requires_ot=False):
|
||||||
self.app_name = app_name
|
self.app_name = app_name
|
||||||
self.title = title
|
self.title = title
|
||||||
self.version = version
|
self.version = version
|
||||||
|
@ -79,6 +80,8 @@ class InstalledGame:
|
||||||
self.executable = executable
|
self.executable = executable
|
||||||
self.launch_parameters = launch_parameters
|
self.launch_parameters = launch_parameters
|
||||||
self.prereq_info = prereq_info
|
self.prereq_info = prereq_info
|
||||||
|
self.can_run_offline = can_run_offline
|
||||||
|
self.requires_ot = requires_ot
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_json(cls, json):
|
def from_json(cls, json):
|
||||||
|
@ -93,4 +96,7 @@ class InstalledGame:
|
||||||
tmp.executable = json.get('executable', '')
|
tmp.executable = json.get('executable', '')
|
||||||
tmp.launch_parameters = json.get('launch_parameters', '')
|
tmp.launch_parameters = json.get('launch_parameters', '')
|
||||||
tmp.prereq_info = json.get('prereq_info', None)
|
tmp.prereq_info = json.get('prereq_info', None)
|
||||||
|
|
||||||
|
tmp.can_run_offline = json.get('can_run_offline', True)
|
||||||
|
tmp.requires_ot = json.get('requires_ot', False)
|
||||||
return tmp
|
return tmp
|
||||||
|
|
Loading…
Reference in a new issue