Compare commits
15 Commits
Author | SHA1 | Date | |
---|---|---|---|
5ce4c62f22 | |||
b80fa43e99 | |||
62f53c0396 | |||
051d4765a4 | |||
365ad9a719 | |||
81f00bdbf6 | |||
44d221ac1b | |||
7054ae2b05 | |||
2288fe01ea | |||
dfa6f7e0be | |||
1746f27193 | |||
c8f9ac9768 | |||
7773b63520 | |||
e4814cfa8e | |||
ba336fe8ed |
71
.github/workflows/codeql-analysis.yml
vendored
Normal file
71
.github/workflows/codeql-analysis.yml
vendored
Normal file
@ -0,0 +1,71 @@
|
||||
# For most projects, this workflow file will not need changing; you simply need
|
||||
# to commit it to your repository.
|
||||
#
|
||||
# You may wish to alter this file to override the set of languages analyzed,
|
||||
# or to provide custom queries or build logic.
|
||||
#
|
||||
# ******** NOTE ********
|
||||
# We have attempted to detect the languages in your repository. Please check
|
||||
# the `language` matrix defined below to confirm you have the correct set of
|
||||
# supported CodeQL languages.
|
||||
#
|
||||
name: "CodeQL"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ master ]
|
||||
pull_request:
|
||||
# The branches below must be a subset of the branches above
|
||||
branches: [ master ]
|
||||
schedule:
|
||||
- cron: '16 0 * * 0'
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
name: Analyze
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
actions: read
|
||||
contents: read
|
||||
security-events: write
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
language: [ 'python' ]
|
||||
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ]
|
||||
# Learn more:
|
||||
# https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v1
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||
# By default, queries listed here will override any specified in a config file.
|
||||
# Prefix the list here with "+" to use these queries and those in the config file.
|
||||
# queries: ./path/to/local/query, your-org/your-repo/queries@main
|
||||
|
||||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||
# If this step fails, then you should remove it and run the build manually (see below)
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v1
|
||||
|
||||
# ℹ️ Command-line programs to run using the OS shell.
|
||||
# 📚 https://git.io/JvXDl
|
||||
|
||||
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
|
||||
# and modify them (or add more) to build your code if your project
|
||||
# uses a compiled language
|
||||
|
||||
#- run: |
|
||||
# make bootstrap
|
||||
# make release
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v1
|
5
Makefile
5
Makefile
@ -52,8 +52,9 @@ clean-test: ## remove test and coverage artifacts
|
||||
rm -fr .pytest_cache
|
||||
|
||||
lint: ## check style with flake8
|
||||
black erepublik tests
|
||||
flake8 erepublik tests
|
||||
isort erepublik examples tests
|
||||
black erepublik examples tests
|
||||
flake8 erepublik examples tests
|
||||
|
||||
test: ## run tests quickly with the default Python
|
||||
python -m unittest
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
__author__ = """Eriks Karls"""
|
||||
__email__ = "eriks@72.lv"
|
||||
__version__ = "0.26.0.1"
|
||||
__version__ = "0.27.1"
|
||||
|
||||
from erepublik.citizen import Citizen
|
||||
|
||||
|
@ -187,15 +187,15 @@ class CitizenBaseAPI:
|
||||
) -> Response:
|
||||
c = [cookie.name for cookie in self._req.cookies if not cookie.has_nonstandard_attr("HttpOnly")]
|
||||
env = dict(l=["tets"], s=[], c=c, m=0)
|
||||
cookies = dict(
|
||||
sh=hashlib.sha256(",".join(env["l"] + env["s"]).encode("utf8")).hexdigest(),
|
||||
ch=hashlib.sha256(",".join(env["c"]).encode("utf8")).hexdigest(),
|
||||
)
|
||||
|
||||
session_hash = hashlib.sha256(",".join(env["l"] + env["s"]).encode("utf8")).hexdigest()
|
||||
cookies_hash = hashlib.sha256(",".join(env["c"]).encode("utf8")).hexdigest()
|
||||
|
||||
cookie_kwargs = dict(
|
||||
expires=int(time.time()) + 120, path="/en/main/sessionUnlock", domain=".www.erepublik.com", secure=True, rest={"HttpOnly": True}
|
||||
)
|
||||
self._req.cookies.set("sh", cookies["sh"], **cookie_kwargs)
|
||||
self._req.cookies.set("ch", cookies["ch"], **cookie_kwargs)
|
||||
self._req.cookies.set("sh", session_hash, **cookie_kwargs)
|
||||
self._req.cookies.set("ch", cookies_hash, **cookie_kwargs)
|
||||
b64_env = utils.b64json(env)
|
||||
data = dict(
|
||||
_token=self.token,
|
||||
|
@ -7,7 +7,7 @@ from decimal import Decimal
|
||||
from itertools import product
|
||||
from threading import Event
|
||||
from time import sleep
|
||||
from typing import Any, Dict, List, NoReturn, Optional, Set, Tuple, Union
|
||||
from typing import Any, Dict, List, NoReturn, Optional, Set, Tuple, TypedDict, Union
|
||||
|
||||
from requests import HTTPError, RequestException, Response
|
||||
|
||||
@ -180,12 +180,21 @@ class BaseCitizen(access_points.CitizenAPI):
|
||||
ugly_js_match = re.search(r'"promotions":\s*(\[{?.*?}?])', html)
|
||||
ugly_js = ugly_js_match.group(1) if ugly_js_match else "null"
|
||||
promos = utils.json_loads(utils.normalize_html_json(ugly_js))
|
||||
if self.promos:
|
||||
self.promos = {k: v for k, v in self.promos.items() if v > self.now}
|
||||
else:
|
||||
self.promos = {}
|
||||
if promos:
|
||||
self.promos = {k: v for k, v in promos.items() if v > self.now}
|
||||
for kind, time_until in self.promos.items():
|
||||
self.reporter.report_promo(kind, time_until)
|
||||
|
||||
try:
|
||||
if promos:
|
||||
for promo in promos:
|
||||
kind = promo["typeId"]
|
||||
time_until = utils.localize_timestamp(promo["expiresAt"])
|
||||
if kind not in self.promos:
|
||||
self.reporter.report_promo(kind, time_until)
|
||||
self.promos[kind] = time_until
|
||||
except Exception: # noqa
|
||||
self.report_error()
|
||||
new_date = re.search(r"var new_date = '(\d*)';", html)
|
||||
if new_date:
|
||||
self.energy.set_reference_time(utils.good_timedelta(self.now, timedelta(seconds=int(new_date.group(1)))))
|
||||
@ -270,20 +279,22 @@ class BaseCitizen(access_points.CitizenAPI):
|
||||
return self._post_main_session_get_challenge(captcha_id, image_id).json()
|
||||
|
||||
def solve_captcha(self, src: str) -> Optional[List[Dict[str, int]]]:
|
||||
class _API_RESULT(dict):
|
||||
class ApiResult(TypedDict):
|
||||
x: int
|
||||
y: int
|
||||
|
||||
class _API_RETURN(dict):
|
||||
class ApiReturn(TypedDict):
|
||||
status: bool
|
||||
message: str
|
||||
result: Optional[List[_API_RESULT]]
|
||||
result: Optional[List[ApiResult]]
|
||||
|
||||
solve_data: _API_RETURN = self.post(
|
||||
"https://api.erep.lv/captcha/api", data=dict(citizen_id=self.details.citizen_id, src=src, key="CaptchaDevAPI")
|
||||
solve_data = ApiReturn(
|
||||
**self.post(
|
||||
"https://api.erep.lv/captcha/api", data=dict(citizen_id=self.details.citizen_id, src=src, password="CaptchaDevAPI")
|
||||
).json()
|
||||
)
|
||||
if solve_data["status"]:
|
||||
return solve_data.get("result")
|
||||
return solve_data["result"]
|
||||
|
||||
@property
|
||||
def inventory(self) -> classes.Inventory:
|
||||
@ -470,13 +481,9 @@ class BaseCitizen(access_points.CitizenAPI):
|
||||
else:
|
||||
icon = "//www.erepublik.net/" + item_data["icon"]
|
||||
|
||||
raw_materials[constants.INDUSTRIES[item_data.get("industryId")]].update(
|
||||
{
|
||||
0: dict(
|
||||
raw_materials[constants.INDUSTRIES[item_data.get("industryId")]][0] = dict(
|
||||
name=item_data.get("name"), amount=item_data["amount"] + (item_data.get("underCostruction", 0) / 100), icon=icon
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
offers: Dict[str, Dict[int, Dict[str, Union[str, int]]]] = {}
|
||||
for offer in self._get_economy_my_market_offers().json():
|
||||
@ -783,7 +790,7 @@ class BaseCitizen(access_points.CitizenAPI):
|
||||
reward = reward[:-1]
|
||||
|
||||
if (title, reward) not in data:
|
||||
data[(title, reward)] = dict(about=about, kind=title, reward=reward, count=1, currency=currency)
|
||||
data[(title, reward)] = dict(about=about, kind=title, reward=reward or 0, count=1, currency=currency)
|
||||
else:
|
||||
data[(title, reward)]["count"] += 1
|
||||
except AttributeError:
|
||||
@ -865,7 +872,7 @@ class BaseCitizen(access_points.CitizenAPI):
|
||||
if re.search(
|
||||
r"Occasionally there are a couple of things which we need to check or to implement in order make "
|
||||
r"your experience in eRepublik more pleasant. <strong>Don\'t worry about ongoing battles, timer "
|
||||
r"will be stopped during maintenance.</strong>",
|
||||
r"will be stopped during maintenance.</strong>|Maintenance. We’ll be back any second now.",
|
||||
response.text,
|
||||
):
|
||||
self.write_warning("eRepublik is having maintenance. Sleeping for 5 mi#nutes")
|
||||
@ -1588,6 +1595,12 @@ class CitizenEconomy(CitizenTravel):
|
||||
if self.config.telegram:
|
||||
self.telegram.report_item_donation(citizen_id, amount, f"{industry} q{quality}")
|
||||
|
||||
def _update_inventory_data(self, *args, **kwargs):
|
||||
super()._update_inventory_data(*args, **kwargs)
|
||||
|
||||
if self.food["total"] < 240 * self.energy.interval:
|
||||
self.buy_food()
|
||||
|
||||
|
||||
class CitizenLeaderBoard(BaseCitizen):
|
||||
def get_aircraft_damage_rankings(self, country: int, weeks: int = 0, mu: int = 0) -> Dict[str, any]:
|
||||
@ -1993,7 +2006,7 @@ class CitizenMilitary(CitizenTravel):
|
||||
energy_used = 0
|
||||
if deployment_id:
|
||||
self.write_warning(
|
||||
"If erepublik responds with HTTP 500 Internal Error, it is kind of ok, because deployment has not finished yet."
|
||||
"If eRepublik responds with HTTP 500 Internal Error, it is kind of ok, because deployment has not finished yet."
|
||||
)
|
||||
deployment_data = self._post_military_fight_deploy_deploy_report_data(deployment_id).json()
|
||||
if not deployment_data.get("error"):
|
||||
@ -2296,7 +2309,7 @@ class CitizenMilitary(CitizenTravel):
|
||||
type="damage",
|
||||
)
|
||||
r_json = r.json()
|
||||
return (r_json.get(str(battle.invader.id)).get("fighterData"), r_json.get(str(battle.defender.id)).get("fighterData"))
|
||||
return r_json.get(str(battle.invader.id)).get("fighterData"), r_json.get(str(battle.defender.id)).get("fighterData")
|
||||
|
||||
def get_battle_division_stats(self, division: classes.BattleDivision) -> Dict[str, Any]:
|
||||
battle = division.battle
|
||||
@ -2616,8 +2629,7 @@ class CitizenTasks(CitizenEconomy):
|
||||
else:
|
||||
self.reporter.report_action("WORK", json_val=js)
|
||||
else:
|
||||
if self.energy.food_fights < 1:
|
||||
seconds = (self.energy.reference_time - self.now).total_seconds()
|
||||
seconds = self.now.timestamp() % 360
|
||||
self.write_warning(f"I don't have energy to work. Will sleep for {seconds}s")
|
||||
self.sleep(seconds)
|
||||
self.work()
|
||||
@ -2643,11 +2655,9 @@ class CitizenTasks(CitizenEconomy):
|
||||
else:
|
||||
self.reporter.report_action("TRAIN", response.json())
|
||||
else:
|
||||
if self.energy.food_fights < len(tgs):
|
||||
large = max(self.energy.reference_time, self.now)
|
||||
sleep_seconds = utils.get_sleep_seconds(large)
|
||||
self.write_warning(f"I don't have energy to train. Will sleep for {sleep_seconds} seconds")
|
||||
self.sleep(sleep_seconds)
|
||||
seconds = self.now.timestamp() % 360
|
||||
self.write_warning(f"I don't have energy to train. Will sleep for {seconds}s")
|
||||
self.sleep(seconds)
|
||||
self.train()
|
||||
|
||||
def work_ot(self):
|
||||
@ -2665,11 +2675,9 @@ class CitizenTasks(CitizenEconomy):
|
||||
self.buy_food(120)
|
||||
self.reporter.report_action("WORK_OT", r.json())
|
||||
elif self.energy.food_fights < 1 and self.ot_points >= 24:
|
||||
if self.energy.food_fights < 1:
|
||||
large = max(self.energy.reference_time, self.now)
|
||||
sleep_seconds = utils.get_sleep_seconds(large)
|
||||
self.write_warning(f"I don't have energy to work OT. Will sleep for {sleep_seconds}s")
|
||||
self.sleep(sleep_seconds)
|
||||
seconds = self.now.timestamp() % 360
|
||||
self.write_warning(f"I don't have energy to work OT. Will sleep for {seconds}s")
|
||||
self.sleep(seconds)
|
||||
self.work_ot()
|
||||
|
||||
def resign_from_employer(self) -> bool:
|
||||
@ -2791,15 +2799,18 @@ class _Citizen(
|
||||
if award_id and title and medal.get("details").get("isWallMaterial"):
|
||||
self._post_main_wall_post_automatic(title.lower(), award_id)
|
||||
|
||||
if params.get("ccValue"):
|
||||
reward = params.get("ccValue")
|
||||
if "ccValue" in params:
|
||||
reward = params.get("ccValue") or 0
|
||||
currency = "Currency"
|
||||
elif params.get("goldValue"):
|
||||
reward = params.get("goldValue")
|
||||
elif "goldValue" in params:
|
||||
reward = params.get("goldValue") or 0
|
||||
currency = "Gold"
|
||||
else:
|
||||
reward = params.get("energyValue")
|
||||
elif "energyValue" in params:
|
||||
reward = params.get("energyValue") or 0
|
||||
currency = "Energy"
|
||||
else:
|
||||
reward = 0
|
||||
currency = "Unknown"
|
||||
|
||||
if (title, reward) not in data:
|
||||
data[(title, reward)] = {
|
||||
@ -2836,8 +2847,8 @@ class _Citizen(
|
||||
self.update_companies()
|
||||
self.update_money()
|
||||
self.update_weekly_challenge()
|
||||
self.send_state_update()
|
||||
self.check_for_notification_medals()
|
||||
self.send_state_update()
|
||||
|
||||
def update_weekly_challenge(self):
|
||||
data = self._get_main_weekly_challenge_data().json()
|
||||
@ -2902,11 +2913,12 @@ class _Citizen(
|
||||
start_time = utils.good_timedelta(start_time.replace(minute=0), timedelta(hours=1))
|
||||
while not self.stop_threads.is_set():
|
||||
start_time = utils.good_timedelta(start_time, timedelta(minutes=10 if self.restricted_ip else 30))
|
||||
self.update_citizen_info()
|
||||
self.update_weekly_challenge()
|
||||
try:
|
||||
self.update_all()
|
||||
except classes.CaptchaSessionError:
|
||||
self.send_state_update()
|
||||
pass
|
||||
self.send_inventory_update()
|
||||
self.update_companies()
|
||||
self.send_my_companies_update()
|
||||
sleep_seconds = (start_time - self.now).total_seconds()
|
||||
self.stop_threads.wait(sleep_seconds if sleep_seconds > 0 else 0)
|
||||
|
@ -1,5 +1,5 @@
|
||||
[bumpversion]
|
||||
current_version = 0.26.0.1
|
||||
current_version = 0.27.1
|
||||
commit = True
|
||||
tag = True
|
||||
parse = (?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)\.?(?P<dev>\d+)?
|
||||
|
6
setup.py
6
setup.py
@ -30,7 +30,7 @@ setup(
|
||||
classifiers=[
|
||||
"Development Status :: 4 - Beta",
|
||||
"Intended Audience :: Developers",
|
||||
"License :: OSI Approved :: GPLv3 License",
|
||||
"License :: OSI Approved :: GNU General Public License v3 (GPLv3)",
|
||||
"Natural Language :: English",
|
||||
"Programming Language :: Python :: 3",
|
||||
"Programming Language :: Python :: 3.8",
|
||||
@ -39,7 +39,7 @@ setup(
|
||||
description="Python package for automated eRepublik playing",
|
||||
entry_points={},
|
||||
install_requires=requirements,
|
||||
license="GPLv3 license",
|
||||
license="GPLv3",
|
||||
long_description=readme + "\n\n" + history,
|
||||
include_package_data=True,
|
||||
keywords="erepublik",
|
||||
@ -50,6 +50,6 @@ setup(
|
||||
test_suite="tests",
|
||||
tests_require=test_requirements,
|
||||
url="https://github.com/eeriks/erepublik/",
|
||||
version="0.26.0.1",
|
||||
version="0.27.1",
|
||||
zip_safe=False,
|
||||
)
|
||||
|
@ -3,10 +3,10 @@
|
||||
|
||||
"""Tests for `erepublik` package."""
|
||||
|
||||
from erepublik import Citizen
|
||||
|
||||
import unittest
|
||||
|
||||
from erepublik import Citizen
|
||||
|
||||
|
||||
class TestErepublik(unittest.TestCase):
|
||||
"""Tests for `erepublik` package."""
|
||||
|
Reference in New Issue
Block a user