Skip to content

Commit b1c4fcc

Browse files
authored
added EX-APP-VERSION handling (#80)
Reject requests with different from ours `EX-APP-VERSION` Signed-off-by: Alexander Piskun <bigcat88@icloud.com>
1 parent 41b9d06 commit b1c4fcc

File tree

5 files changed

+73
-5
lines changed

5 files changed

+73
-5
lines changed

.run/_app_security_checks.run.xml

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<component name="ProjectRunConfigurationManager">
2+
<configuration default="false" name="_app_security_checks" type="PythonConfigurationType" factoryName="Python" nameIsGenerated="true">
3+
<module name="nc_py_api" />
4+
<option name="INTERPRETER_OPTIONS" value="" />
5+
<option name="PARENT_ENVS" value="true" />
6+
<envs>
7+
<env name="APP_ID" value="nc_py_api" />
8+
<env name="APP_SECRET" value="12345" />
9+
<env name="PYTHONUNBUFFERED" value="1" />
10+
</envs>
11+
<option name="SDK_HOME" value="" />
12+
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/tests" />
13+
<option name="IS_MODULE_SDK" value="true" />
14+
<option name="ADD_CONTENT_ROOTS" value="true" />
15+
<option name="ADD_SOURCE_ROOTS" value="true" />
16+
<EXTENSION ID="PythonCoverageRunConfigurationExtension" runner="coverage.py" />
17+
<option name="SCRIPT_NAME" value="$PROJECT_DIR$/tests/_app_security_checks.py" />
18+
<option name="PARAMETERS" value="http://127.0.0.1:9009" />
19+
<option name="SHOW_COMMAND_LINE" value="false" />
20+
<option name="EMULATE_TERMINAL" value="false" />
21+
<option name="MODULE_MODE" value="false" />
22+
<option name="REDIRECT_INPUT" value="false" />
23+
<option name="INPUT_FILE" value="" />
24+
<method v="2" />
25+
</configuration>
26+
</component>

.run/register.run.xml

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<component name="ProjectRunConfigurationManager">
2+
<configuration default="false" name="register" type="PythonConfigurationType" factoryName="Python">
3+
<module name="nc_py_api" />
4+
<option name="INTERPRETER_OPTIONS" value="" />
5+
<option name="PARENT_ENVS" value="true" />
6+
<envs>
7+
<env name="APP_ID" value="nc_py_api" />
8+
<env name="APP_PORT" value="9009" />
9+
<env name="APP_SECRET" value="12345" />
10+
<env name="APP_VERSION" value="1.0.0" />
11+
<env name="NEXTCLOUD_URL" value="http://nextcloud.local/index.php" />
12+
<env name="PYTHONUNBUFFERED" value="1" />
13+
</envs>
14+
<option name="SDK_HOME" value="" />
15+
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/tests" />
16+
<option name="IS_MODULE_SDK" value="true" />
17+
<option name="ADD_CONTENT_ROOTS" value="true" />
18+
<option name="ADD_SOURCE_ROOTS" value="true" />
19+
<EXTENSION ID="PythonCoverageRunConfigurationExtension" runner="coverage.py" />
20+
<option name="SCRIPT_NAME" value="$PROJECT_DIR$/tests/_install.py" />
21+
<option name="PARAMETERS" value="" />
22+
<option name="SHOW_COMMAND_LINE" value="false" />
23+
<option name="EMULATE_TERMINAL" value="false" />
24+
<option name="MODULE_MODE" value="false" />
25+
<option name="REDIRECT_INPUT" value="false" />
26+
<option name="INPUT_FILE" value="" />
27+
<method v="2" />
28+
</configuration>
29+
</component>

nc_py_api/_session.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -369,7 +369,7 @@ def sign_request(self, method: str, url_params: str, headers: dict, data: Option
369369
if "NC-USER-ID" in sign_headers:
370370
headers["NC-USER-ID"] = sign_headers["NC-USER-ID"]
371371

372-
def sign_check(self, request: Request):
372+
def sign_check(self, request: Request) -> None:
373373
current_time = int(datetime.now(timezone.utc).timestamp())
374374
headers = {
375375
"AE-VERSION": request.headers.get("AE-VERSION", ""),
@@ -386,8 +386,9 @@ def sign_check(self, request: Request):
386386
if empty_headers:
387387
raise ValueError(f"Missing required headers:{empty_headers}")
388388

389-
if headers["EX-APP-VERSION"] != self.adapter.headers.get("EX-APP-VERSION"):
390-
pass # TO-DO: we should reject all requests and ask server to update our app version
389+
our_version = self.adapter.headers.get("EX-APP-VERSION", "")
390+
if headers["EX-APP-VERSION"] != our_version:
391+
raise ValueError(f"Invalid EX-APP-VERSION:{headers['EX-APP-VERSION']} <=> {our_version}")
391392

392393
request_time = int(headers["AE-SIGN-TIME"])
393394
if request_time < current_time - 5 * 60 or request_time > current_time + 5 * 60:
@@ -411,4 +412,3 @@ def sign_check(self, request: Request):
411412
raise ValueError(f"Invalid AE-DATA-HASH:{ae_data_hash} !={headers['AE-DATA-HASH']}")
412413
if headers["EX-APP-ID"] != self.cfg.app_name:
413414
raise ValueError(f"Invalid EX-APP-ID:{headers['EX-APP-ID']} != {self.cfg.app_name}")
414-
return True

nc_py_api/_version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
"""Version of nc_py_api."""
22

3-
__version__ = "0.0.29"
3+
__version__ = "0.0.30.dev"

tests/_app_security_checks.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,19 @@ def sign_request(url: str, req_headers: dict, time: int = 0):
5858
# Invalid AE-DATA-HASH
5959
result = requests.put(request_url, headers=headers, data=b"some_data")
6060
assert result.status_code == 401
61+
# Invalid EX-APP-VERSION
62+
sign_request("/sec_check?value=0", headers)
63+
result = requests.put(request_url, headers=headers)
64+
assert result.status_code == 200
65+
old_version = headers["EX-APP-VERSION"]
66+
headers["EX-APP-VERSION"] = "999.0.0"
67+
sign_request("/sec_check?value=0", headers)
68+
result = requests.put(request_url, headers=headers)
69+
assert result.status_code == 401
70+
headers["EX-APP-VERSION"] = old_version
71+
sign_request("/sec_check?value=0", headers)
72+
result = requests.put(request_url, headers=headers)
73+
assert result.status_code == 200
6174
# Sign time
6275
sign_request("/sec_check?value=0", headers, time=int(datetime.now(timezone.utc).timestamp()))
6376
result = requests.put(request_url, headers=headers)

0 commit comments

Comments
 (0)