Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitce9daf7

Browse files
authored
feat(crypto): decrypt secret objects (#482)
Add support for `isSecret` objects and arrays in input schema and thenew form of encrypted value:```ENCRYPTED_JSON_VALUE:{FIELD_SCHEMA_HASH}:{ENCRYPTED_PASSWORD}:{ENCRYPTED_VALUE}```More context hereapify/apify-shared-js#515
1 parent59b50d1 commitce9daf7

File tree

3 files changed

+36
-10
lines changed

3 files changed

+36
-10
lines changed

‎src/apify/_consts.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,6 @@
66
EVENT_LISTENERS_TIMEOUT=timedelta(seconds=5)
77

88
BASE64_REGEXP='[-A-Za-z0-9+/]*={0,3}'
9-
ENCRYPTED_INPUT_VALUE_PREFIX='ENCRYPTED_VALUE'
10-
ENCRYPTED_INPUT_VALUE_REGEXP=re.compile(f'^{ENCRYPTED_INPUT_VALUE_PREFIX}:({BASE64_REGEXP}):({BASE64_REGEXP})$')
9+
ENCRYPTED_STRING_VALUE_PREFIX='ENCRYPTED_VALUE'
10+
ENCRYPTED_JSON_VALUE_PREFIX='ENCRYPTED_JSON'
11+
ENCRYPTED_INPUT_VALUE_REGEXP=re.compile(f'^({ENCRYPTED_STRING_VALUE_PREFIX}|{ENCRYPTED_JSON_VALUE_PREFIX}):(?:({BASE64_REGEXP}):)?({BASE64_REGEXP}):({BASE64_REGEXP})$')

‎src/apify/_crypto.py

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
importbase64
44
importhashlib
55
importhmac
6+
importjson
67
importstring
78
fromtypingimportAny
89

@@ -14,7 +15,7 @@
1415
fromapify_shared.utilsimportignore_docs
1516
fromcrawlee._utils.cryptoimportcrypto_random_object_id
1617

17-
fromapify._constsimportENCRYPTED_INPUT_VALUE_REGEXP
18+
fromapify._constsimportENCRYPTED_INPUT_VALUE_REGEXP,ENCRYPTED_STRING_VALUE_PREFIX,ENCRYPTED_JSON_VALUE_PREFIX
1819

1920
ENCRYPTION_KEY_LENGTH=32
2021
ENCRYPTION_IV_LENGTH=16
@@ -147,14 +148,20 @@ def decrypt_input_secrets(private_key: rsa.RSAPrivateKey, input_data: Any) -> An
147148
ifisinstance(value,str):
148149
match=ENCRYPTED_INPUT_VALUE_REGEXP.fullmatch(value)
149150
ifmatch:
150-
encrypted_password=match.group(1)
151-
encrypted_value=match.group(2)
152-
input_data[key]=private_decrypt(
151+
prefix=match.group(1)
152+
encrypted_password=match.group(3)
153+
encrypted_value=match.group(4)
154+
decrypted_value=private_decrypt(
153155
encrypted_password,
154156
encrypted_value,
155157
private_key=private_key,
156158
)
157159

160+
ifprefix==ENCRYPTED_STRING_VALUE_PREFIX:
161+
input_data[key]=decrypted_value
162+
elifprefix==ENCRYPTED_JSON_VALUE_PREFIX:
163+
input_data[key]=json.loads(decrypted_value)
164+
158165
returninput_data
159166

160167

‎tests/unit/actor/test_actor_key_value_store.py

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
from ..test_cryptoimportPRIVATE_KEY_PASSWORD,PRIVATE_KEY_PEM_BASE64,PUBLIC_KEY
1111
fromapifyimportActor
12-
fromapify._constsimportENCRYPTED_INPUT_VALUE_PREFIX
12+
fromapify._constsimportENCRYPTED_STRING_VALUE_PREFIX,ENCRYPTED_JSON_VALUE_PREFIX
1313
fromapify._cryptoimportpublic_encrypt
1414

1515
ifTYPE_CHECKING:
@@ -74,11 +74,26 @@ async def test_get_input_with_encrypted_secrets(
7474
monkeypatch.setenv(ApifyEnvVars.INPUT_SECRETS_PRIVATE_KEY_PASSPHRASE,PRIVATE_KEY_PASSWORD)
7575

7676
input_key='INPUT'
77+
secret_string_legacy='secret-string'
7778
secret_string='secret-string'
78-
encrypted_secret=public_encrypt(secret_string,public_key=PUBLIC_KEY)
79+
secret_object= {'foo':'bar','baz':'qux'}
80+
secret_array= ['foo','bar','baz']
81+
82+
# The legacy encryption format uses ENCRYPTED_STRING_VALUE_PREFIX prefix, value in raw string and does not include schemahash.
83+
# The new format uses ENCRYPTED_JSON_VALUE_PREFIX prefix, value in JSON format and includes schemahash.
84+
# We are testing both formats to ensure backward compatibility.
85+
86+
encrypted_string_legacy=public_encrypt(secret_string_legacy,public_key=PUBLIC_KEY)
87+
encrypted_string=public_encrypt(json_dumps(secret_string),public_key=PUBLIC_KEY)
88+
encrypted_object=public_encrypt(json_dumps(secret_object),public_key=PUBLIC_KEY)
89+
encrypted_array=public_encrypt(json_dumps(secret_array),public_key=PUBLIC_KEY)
90+
7991
input_with_secret= {
8092
'foo':'bar',
81-
'secret':f'{ENCRYPTED_INPUT_VALUE_PREFIX}:{encrypted_secret["encrypted_password"]}:{encrypted_secret["encrypted_value"]}',# noqa: E501
93+
'secret_string_legacy':f'{ENCRYPTED_STRING_VALUE_PREFIX}:{encrypted_string_legacy["encrypted_password"]}:{encrypted_string_legacy["encrypted_value"]}',
94+
'secret_string':f'{ENCRYPTED_JSON_VALUE_PREFIX}:schemahash:{encrypted_string["encrypted_password"]}:{encrypted_string["encrypted_value"]}',
95+
'secret_object':f'{ENCRYPTED_JSON_VALUE_PREFIX}:schemahash:{encrypted_object["encrypted_password"]}:{encrypted_object["encrypted_value"]}',
96+
'secret_array':f'{ENCRYPTED_JSON_VALUE_PREFIX}:schemahash:{encrypted_array["encrypted_password"]}:{encrypted_array["encrypted_value"]}',
8297
}
8398

8499
awaitmemory_storage_client.key_value_stores().get_or_create(id='default')
@@ -91,4 +106,7 @@ async def test_get_input_with_encrypted_secrets(
91106
asyncwithActorasmy_actor:
92107
input=awaitmy_actor.get_input()# noqa: A001
93108
assertinput['foo']==input_with_secret['foo']
94-
assertinput['secret']==secret_string
109+
assertinput['secret_string_legacy']==secret_string_legacy
110+
assertinput['secret_string']==secret_string
111+
assertinput['secret_object']==secret_object
112+
assertinput['secret_array']==secret_array

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp