CCencrypt 0.3.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,214 @@
1
+ Metadata-Version: 2.4
2
+ Name: CCencrypt
3
+ Version: 0.3.0
4
+ Summary: Card encryption and tokenisation for Adyen, CyberSource, eWay, Stripe, Braintree, Shopify and PayDock
5
+ Author: itsregza
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/itsregza/CCencrypt
8
+ Project-URL: Repository, https://github.com/itsregza/CCencrypt
9
+ Requires-Python: >=3.9
10
+ Description-Content-Type: text/markdown
11
+ Requires-Dist: cryptography>=42.0.0
12
+ Requires-Dist: requests>=2.28.0
13
+
14
+ <p align="center">
15
+ <img src="https://raw.githubusercontent.com/itsregza/CCencrypt/main/assets/banner.svg" alt="CCencrypt" width="520">
16
+ </p>
17
+
18
+ <p align="center">Card encryption and tokenisation for Python.</p>
19
+
20
+ | Processor | Function | Type | Returns |
21
+ |---|---|---|---|
22
+ | Adyen | `ccadyen` | Encrypt | dict of 4 encrypted fields |
23
+ | CyberSource Flex | `cccybersource` / `cccybersource_token` | Encrypt / Tokenise | JWE / transient token |
24
+ | eWay | `cceway` / `cceway_card` | Encrypt | `eCrypted:...` strings |
25
+ | Stripe | `ccstripe` | Tokenise | `pm_...` payment method id |
26
+ | Braintree | `ccbraintree` | Tokenise | `tokencc_...` nonce |
27
+ | Shopify | `ccshopify` | Tokenise | card session id |
28
+ | PayDock | `ccpaydock` | Tokenise | one-time card token |
29
+
30
+ ## Install
31
+
32
+ ```bash
33
+ pip install ccencrypt
34
+ ```
35
+
36
+ ## Card details
37
+
38
+ Every function cleans the card details before using them, so any of these work:
39
+
40
+ | Field | Accepted |
41
+ |---|---|
42
+ | card | `"4242424242424242"`, `"4242 4242 4242 4242"`, `"4242-4242-4242-4242"` |
43
+ | month | `1`, `"1"`, `"01"` |
44
+ | year | `29`, `"29"`, `2029`, `"2029"` |
45
+
46
+ Month and year are always separate arguments. If you have `"01/29"`, split it first:
47
+
48
+ ```python
49
+ month, year = "01/29".split("/")
50
+ ```
51
+
52
+ ## Proxies
53
+
54
+ You can pass a proxy for the process. Some processors like paydock will ratelimit so its important to use proxies:
55
+
56
+ ```python
57
+ token = ccencrypt.ccpaydock(public_key, card, month, year, cvv, name, proxy="http://user:pass@host:port")
58
+ ```
59
+
60
+ ## Errors
61
+
62
+ Tokenise functions raise `RuntimeError` with the status code and response body when the processor rejects the request.
63
+
64
+ ---
65
+
66
+ ## Encryption
67
+
68
+ ### Adyen
69
+
70
+ `encrypt_key` is the site's Adyen public key (`10001|A532...`).
71
+
72
+ ```python
73
+ import ccencrypt
74
+
75
+ result = ccencrypt.ccadyen(
76
+ encrypt_key="10001|A532...",
77
+ card="4242424242424242",
78
+ month="12",
79
+ year="2029",
80
+ cvc="123",
81
+ client_key="live_...",
82
+ domain="https://example.com",
83
+ )
84
+
85
+ result["encryptedCardNumber"]
86
+ result["encryptedExpiryMonth"]
87
+ result["encryptedExpiryYear"]
88
+ result["encryptedSecurityCode"]
89
+ ```
90
+
91
+ `client_key` and `domain` are optional, but pass the site's own values when you have them.
92
+
93
+ `version` defaults to `"4.5.0"` (Secured Fields). For sites on legacy encryption (`adyenjs_0_1_XX$...`), pass `"0_1_18"`, `"0_1_22"`, `"0_1_23"`, `"0_1_24"` or `"0_1_25"`. Legacy versions ignore `client_key` and `domain`.
94
+
95
+ ```python
96
+ result = ccencrypt.ccadyen(encrypt_key, card, month, year, cvc, version="0_1_25")
97
+ ```
98
+
99
+ To encrypt a custom legacy payload such as `holderName`:
100
+
101
+ ```python
102
+ from ccencrypt.adyen import parse_public_key
103
+
104
+ blob = ccencrypt.cse_encrypt(
105
+ {"holderName": "John Smith", "generationtime": "2029-01-01T00:00:00.000Z"},
106
+ parse_public_key("10001|A532..."),
107
+ version="0_1_25",
108
+ )
109
+ ```
110
+
111
+ ### CyberSource Flex
112
+
113
+ `context` is the capture context JWT from the site's CyberSource init endpoint.
114
+
115
+ Encrypt and exchange for a transient token in one call:
116
+
117
+ ```python
118
+ token = ccencrypt.cccybersource_token(
119
+ card="4242424242424242",
120
+ month="12",
121
+ year="2029",
122
+ cvv="123",
123
+ context=context,
124
+ origin="https://www.example.com",
125
+ user_agent="Mozilla/5.0 ...",
126
+ )
127
+ ```
128
+
129
+ For Microform sites, pass `microform=True` instead of `origin`.
130
+
131
+ To encrypt only, use `cccybersource` with the same card arguments and `context`. It returns a JWE that you POST yourself to `https://flex.cybersource.com/flex/v2/tokens` as `application/jwt`.
132
+
133
+ ### eWay
134
+
135
+ `encrypt_key` is the `data-eway-encrypt-key` value from the site's payment form.
136
+
137
+ ```python
138
+ fields = ccencrypt.cceway_card(encrypt_key, card="4242424242424242", cvv="123")
139
+
140
+ fields["EWAY_CARDNUMBER"]
141
+ fields["EWAY_CARDCVN"]
142
+ ```
143
+
144
+ To encrypt a single value, use `ccencrypt.cceway(encrypt_key, value)`.
145
+
146
+ ---
147
+
148
+ ## Tokenisation
149
+
150
+ ### Stripe
151
+
152
+ `key` is the site's publishable key (`pk_live_...`), sent as `key=` in the site's requests to `api.stripe.com`.
153
+
154
+ ```python
155
+ pm = ccencrypt.ccstripe(
156
+ key="pk_live_...",
157
+ card="4242424242424242",
158
+ month="12",
159
+ year="2029",
160
+ cvc="123",
161
+ name="John Smith",
162
+ )
163
+ ```
164
+
165
+ If the site's requests also send `_stripe_account=acct_...`, pass it as `account`.
166
+
167
+ ### Braintree
168
+
169
+ `client_token` is the base64 client token the site hands to Braintree. A raw `authorizationFingerprint` also works.
170
+
171
+ ```python
172
+ nonce = ccencrypt.ccbraintree(
173
+ client_token="eyJ2ZXJzaW9uIjoy...",
174
+ card="4242424242424242",
175
+ month="12",
176
+ year="2029",
177
+ cvv="123",
178
+ name="John Smith",
179
+ )
180
+ ```
181
+
182
+ ### Shopify
183
+
184
+ `domain` is the store's domain, without `https://` or `www.`.
185
+
186
+ ```python
187
+ session_id = ccencrypt.ccshopify(
188
+ domain="example.com.au",
189
+ card="4242424242424242",
190
+ month="12",
191
+ year="2029",
192
+ cvv="123",
193
+ name="John Smith",
194
+ )
195
+ ```
196
+
197
+ The returned id goes into the checkout's payment as the card `sessionId`.
198
+
199
+ ### PayDock
200
+
201
+ `public_key` is the site's PayDock public key, sent as `x-user-public-key` in the site's requests to `api.paydock.com`.
202
+
203
+ ```python
204
+ token = ccencrypt.ccpaydock(
205
+ public_key="5b12b8af...",
206
+ card="4242424242424242",
207
+ month="12",
208
+ year="2029",
209
+ cvv="123",
210
+ name="John Smith",
211
+ )
212
+ ```
213
+
214
+ If the site's token request includes a `gateway_id`, pass it as `gateway_id`.
@@ -0,0 +1,19 @@
1
+ README.md
2
+ pyproject.toml
3
+ CCencrypt.egg-info/PKG-INFO
4
+ CCencrypt.egg-info/SOURCES.txt
5
+ CCencrypt.egg-info/dependency_links.txt
6
+ CCencrypt.egg-info/requires.txt
7
+ CCencrypt.egg-info/top_level.txt
8
+ ccencrypt/__init__.py
9
+ ccencrypt/adyen.py
10
+ ccencrypt/adyen_cse.py
11
+ ccencrypt/braintree.py
12
+ ccencrypt/cybersource.py
13
+ ccencrypt/eway.py
14
+ ccencrypt/paydock.py
15
+ ccencrypt/shopify.py
16
+ ccencrypt/stripe.py
17
+ ccencrypt/helpers/__init__.py
18
+ ccencrypt/helpers/card.py
19
+ ccencrypt/helpers/encoding.py
@@ -0,0 +1,2 @@
1
+ cryptography>=42.0.0
2
+ requests>=2.28.0
@@ -0,0 +1 @@
1
+ ccencrypt
@@ -0,0 +1,214 @@
1
+ Metadata-Version: 2.4
2
+ Name: CCencrypt
3
+ Version: 0.3.0
4
+ Summary: Card encryption and tokenisation for Adyen, CyberSource, eWay, Stripe, Braintree, Shopify and PayDock
5
+ Author: itsregza
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/itsregza/CCencrypt
8
+ Project-URL: Repository, https://github.com/itsregza/CCencrypt
9
+ Requires-Python: >=3.9
10
+ Description-Content-Type: text/markdown
11
+ Requires-Dist: cryptography>=42.0.0
12
+ Requires-Dist: requests>=2.28.0
13
+
14
+ <p align="center">
15
+ <img src="https://raw.githubusercontent.com/itsregza/CCencrypt/main/assets/banner.svg" alt="CCencrypt" width="520">
16
+ </p>
17
+
18
+ <p align="center">Card encryption and tokenisation for Python.</p>
19
+
20
+ | Processor | Function | Type | Returns |
21
+ |---|---|---|---|
22
+ | Adyen | `ccadyen` | Encrypt | dict of 4 encrypted fields |
23
+ | CyberSource Flex | `cccybersource` / `cccybersource_token` | Encrypt / Tokenise | JWE / transient token |
24
+ | eWay | `cceway` / `cceway_card` | Encrypt | `eCrypted:...` strings |
25
+ | Stripe | `ccstripe` | Tokenise | `pm_...` payment method id |
26
+ | Braintree | `ccbraintree` | Tokenise | `tokencc_...` nonce |
27
+ | Shopify | `ccshopify` | Tokenise | card session id |
28
+ | PayDock | `ccpaydock` | Tokenise | one-time card token |
29
+
30
+ ## Install
31
+
32
+ ```bash
33
+ pip install ccencrypt
34
+ ```
35
+
36
+ ## Card details
37
+
38
+ Every function cleans the card details before using them, so any of these work:
39
+
40
+ | Field | Accepted |
41
+ |---|---|
42
+ | card | `"4242424242424242"`, `"4242 4242 4242 4242"`, `"4242-4242-4242-4242"` |
43
+ | month | `1`, `"1"`, `"01"` |
44
+ | year | `29`, `"29"`, `2029`, `"2029"` |
45
+
46
+ Month and year are always separate arguments. If you have `"01/29"`, split it first:
47
+
48
+ ```python
49
+ month, year = "01/29".split("/")
50
+ ```
51
+
52
+ ## Proxies
53
+
54
+ You can pass a proxy for the process. Some processors like paydock will ratelimit so its important to use proxies:
55
+
56
+ ```python
57
+ token = ccencrypt.ccpaydock(public_key, card, month, year, cvv, name, proxy="http://user:pass@host:port")
58
+ ```
59
+
60
+ ## Errors
61
+
62
+ Tokenise functions raise `RuntimeError` with the status code and response body when the processor rejects the request.
63
+
64
+ ---
65
+
66
+ ## Encryption
67
+
68
+ ### Adyen
69
+
70
+ `encrypt_key` is the site's Adyen public key (`10001|A532...`).
71
+
72
+ ```python
73
+ import ccencrypt
74
+
75
+ result = ccencrypt.ccadyen(
76
+ encrypt_key="10001|A532...",
77
+ card="4242424242424242",
78
+ month="12",
79
+ year="2029",
80
+ cvc="123",
81
+ client_key="live_...",
82
+ domain="https://example.com",
83
+ )
84
+
85
+ result["encryptedCardNumber"]
86
+ result["encryptedExpiryMonth"]
87
+ result["encryptedExpiryYear"]
88
+ result["encryptedSecurityCode"]
89
+ ```
90
+
91
+ `client_key` and `domain` are optional, but pass the site's own values when you have them.
92
+
93
+ `version` defaults to `"4.5.0"` (Secured Fields). For sites on legacy encryption (`adyenjs_0_1_XX$...`), pass `"0_1_18"`, `"0_1_22"`, `"0_1_23"`, `"0_1_24"` or `"0_1_25"`. Legacy versions ignore `client_key` and `domain`.
94
+
95
+ ```python
96
+ result = ccencrypt.ccadyen(encrypt_key, card, month, year, cvc, version="0_1_25")
97
+ ```
98
+
99
+ To encrypt a custom legacy payload such as `holderName`:
100
+
101
+ ```python
102
+ from ccencrypt.adyen import parse_public_key
103
+
104
+ blob = ccencrypt.cse_encrypt(
105
+ {"holderName": "John Smith", "generationtime": "2029-01-01T00:00:00.000Z"},
106
+ parse_public_key("10001|A532..."),
107
+ version="0_1_25",
108
+ )
109
+ ```
110
+
111
+ ### CyberSource Flex
112
+
113
+ `context` is the capture context JWT from the site's CyberSource init endpoint.
114
+
115
+ Encrypt and exchange for a transient token in one call:
116
+
117
+ ```python
118
+ token = ccencrypt.cccybersource_token(
119
+ card="4242424242424242",
120
+ month="12",
121
+ year="2029",
122
+ cvv="123",
123
+ context=context,
124
+ origin="https://www.example.com",
125
+ user_agent="Mozilla/5.0 ...",
126
+ )
127
+ ```
128
+
129
+ For Microform sites, pass `microform=True` instead of `origin`.
130
+
131
+ To encrypt only, use `cccybersource` with the same card arguments and `context`. It returns a JWE that you POST yourself to `https://flex.cybersource.com/flex/v2/tokens` as `application/jwt`.
132
+
133
+ ### eWay
134
+
135
+ `encrypt_key` is the `data-eway-encrypt-key` value from the site's payment form.
136
+
137
+ ```python
138
+ fields = ccencrypt.cceway_card(encrypt_key, card="4242424242424242", cvv="123")
139
+
140
+ fields["EWAY_CARDNUMBER"]
141
+ fields["EWAY_CARDCVN"]
142
+ ```
143
+
144
+ To encrypt a single value, use `ccencrypt.cceway(encrypt_key, value)`.
145
+
146
+ ---
147
+
148
+ ## Tokenisation
149
+
150
+ ### Stripe
151
+
152
+ `key` is the site's publishable key (`pk_live_...`), sent as `key=` in the site's requests to `api.stripe.com`.
153
+
154
+ ```python
155
+ pm = ccencrypt.ccstripe(
156
+ key="pk_live_...",
157
+ card="4242424242424242",
158
+ month="12",
159
+ year="2029",
160
+ cvc="123",
161
+ name="John Smith",
162
+ )
163
+ ```
164
+
165
+ If the site's requests also send `_stripe_account=acct_...`, pass it as `account`.
166
+
167
+ ### Braintree
168
+
169
+ `client_token` is the base64 client token the site hands to Braintree. A raw `authorizationFingerprint` also works.
170
+
171
+ ```python
172
+ nonce = ccencrypt.ccbraintree(
173
+ client_token="eyJ2ZXJzaW9uIjoy...",
174
+ card="4242424242424242",
175
+ month="12",
176
+ year="2029",
177
+ cvv="123",
178
+ name="John Smith",
179
+ )
180
+ ```
181
+
182
+ ### Shopify
183
+
184
+ `domain` is the store's domain, without `https://` or `www.`.
185
+
186
+ ```python
187
+ session_id = ccencrypt.ccshopify(
188
+ domain="example.com.au",
189
+ card="4242424242424242",
190
+ month="12",
191
+ year="2029",
192
+ cvv="123",
193
+ name="John Smith",
194
+ )
195
+ ```
196
+
197
+ The returned id goes into the checkout's payment as the card `sessionId`.
198
+
199
+ ### PayDock
200
+
201
+ `public_key` is the site's PayDock public key, sent as `x-user-public-key` in the site's requests to `api.paydock.com`.
202
+
203
+ ```python
204
+ token = ccencrypt.ccpaydock(
205
+ public_key="5b12b8af...",
206
+ card="4242424242424242",
207
+ month="12",
208
+ year="2029",
209
+ cvv="123",
210
+ name="John Smith",
211
+ )
212
+ ```
213
+
214
+ If the site's token request includes a `gateway_id`, pass it as `gateway_id`.
@@ -0,0 +1,201 @@
1
+ <p align="center">
2
+ <img src="https://raw.githubusercontent.com/itsregza/CCencrypt/main/assets/banner.svg" alt="CCencrypt" width="520">
3
+ </p>
4
+
5
+ <p align="center">Card encryption and tokenisation for Python.</p>
6
+
7
+ | Processor | Function | Type | Returns |
8
+ |---|---|---|---|
9
+ | Adyen | `ccadyen` | Encrypt | dict of 4 encrypted fields |
10
+ | CyberSource Flex | `cccybersource` / `cccybersource_token` | Encrypt / Tokenise | JWE / transient token |
11
+ | eWay | `cceway` / `cceway_card` | Encrypt | `eCrypted:...` strings |
12
+ | Stripe | `ccstripe` | Tokenise | `pm_...` payment method id |
13
+ | Braintree | `ccbraintree` | Tokenise | `tokencc_...` nonce |
14
+ | Shopify | `ccshopify` | Tokenise | card session id |
15
+ | PayDock | `ccpaydock` | Tokenise | one-time card token |
16
+
17
+ ## Install
18
+
19
+ ```bash
20
+ pip install ccencrypt
21
+ ```
22
+
23
+ ## Card details
24
+
25
+ Every function cleans the card details before using them, so any of these work:
26
+
27
+ | Field | Accepted |
28
+ |---|---|
29
+ | card | `"4242424242424242"`, `"4242 4242 4242 4242"`, `"4242-4242-4242-4242"` |
30
+ | month | `1`, `"1"`, `"01"` |
31
+ | year | `29`, `"29"`, `2029`, `"2029"` |
32
+
33
+ Month and year are always separate arguments. If you have `"01/29"`, split it first:
34
+
35
+ ```python
36
+ month, year = "01/29".split("/")
37
+ ```
38
+
39
+ ## Proxies
40
+
41
+ You can pass a proxy for the process. Some processors like paydock will ratelimit so its important to use proxies:
42
+
43
+ ```python
44
+ token = ccencrypt.ccpaydock(public_key, card, month, year, cvv, name, proxy="http://user:pass@host:port")
45
+ ```
46
+
47
+ ## Errors
48
+
49
+ Tokenise functions raise `RuntimeError` with the status code and response body when the processor rejects the request.
50
+
51
+ ---
52
+
53
+ ## Encryption
54
+
55
+ ### Adyen
56
+
57
+ `encrypt_key` is the site's Adyen public key (`10001|A532...`).
58
+
59
+ ```python
60
+ import ccencrypt
61
+
62
+ result = ccencrypt.ccadyen(
63
+ encrypt_key="10001|A532...",
64
+ card="4242424242424242",
65
+ month="12",
66
+ year="2029",
67
+ cvc="123",
68
+ client_key="live_...",
69
+ domain="https://example.com",
70
+ )
71
+
72
+ result["encryptedCardNumber"]
73
+ result["encryptedExpiryMonth"]
74
+ result["encryptedExpiryYear"]
75
+ result["encryptedSecurityCode"]
76
+ ```
77
+
78
+ `client_key` and `domain` are optional, but pass the site's own values when you have them.
79
+
80
+ `version` defaults to `"4.5.0"` (Secured Fields). For sites on legacy encryption (`adyenjs_0_1_XX$...`), pass `"0_1_18"`, `"0_1_22"`, `"0_1_23"`, `"0_1_24"` or `"0_1_25"`. Legacy versions ignore `client_key` and `domain`.
81
+
82
+ ```python
83
+ result = ccencrypt.ccadyen(encrypt_key, card, month, year, cvc, version="0_1_25")
84
+ ```
85
+
86
+ To encrypt a custom legacy payload such as `holderName`:
87
+
88
+ ```python
89
+ from ccencrypt.adyen import parse_public_key
90
+
91
+ blob = ccencrypt.cse_encrypt(
92
+ {"holderName": "John Smith", "generationtime": "2029-01-01T00:00:00.000Z"},
93
+ parse_public_key("10001|A532..."),
94
+ version="0_1_25",
95
+ )
96
+ ```
97
+
98
+ ### CyberSource Flex
99
+
100
+ `context` is the capture context JWT from the site's CyberSource init endpoint.
101
+
102
+ Encrypt and exchange for a transient token in one call:
103
+
104
+ ```python
105
+ token = ccencrypt.cccybersource_token(
106
+ card="4242424242424242",
107
+ month="12",
108
+ year="2029",
109
+ cvv="123",
110
+ context=context,
111
+ origin="https://www.example.com",
112
+ user_agent="Mozilla/5.0 ...",
113
+ )
114
+ ```
115
+
116
+ For Microform sites, pass `microform=True` instead of `origin`.
117
+
118
+ To encrypt only, use `cccybersource` with the same card arguments and `context`. It returns a JWE that you POST yourself to `https://flex.cybersource.com/flex/v2/tokens` as `application/jwt`.
119
+
120
+ ### eWay
121
+
122
+ `encrypt_key` is the `data-eway-encrypt-key` value from the site's payment form.
123
+
124
+ ```python
125
+ fields = ccencrypt.cceway_card(encrypt_key, card="4242424242424242", cvv="123")
126
+
127
+ fields["EWAY_CARDNUMBER"]
128
+ fields["EWAY_CARDCVN"]
129
+ ```
130
+
131
+ To encrypt a single value, use `ccencrypt.cceway(encrypt_key, value)`.
132
+
133
+ ---
134
+
135
+ ## Tokenisation
136
+
137
+ ### Stripe
138
+
139
+ `key` is the site's publishable key (`pk_live_...`), sent as `key=` in the site's requests to `api.stripe.com`.
140
+
141
+ ```python
142
+ pm = ccencrypt.ccstripe(
143
+ key="pk_live_...",
144
+ card="4242424242424242",
145
+ month="12",
146
+ year="2029",
147
+ cvc="123",
148
+ name="John Smith",
149
+ )
150
+ ```
151
+
152
+ If the site's requests also send `_stripe_account=acct_...`, pass it as `account`.
153
+
154
+ ### Braintree
155
+
156
+ `client_token` is the base64 client token the site hands to Braintree. A raw `authorizationFingerprint` also works.
157
+
158
+ ```python
159
+ nonce = ccencrypt.ccbraintree(
160
+ client_token="eyJ2ZXJzaW9uIjoy...",
161
+ card="4242424242424242",
162
+ month="12",
163
+ year="2029",
164
+ cvv="123",
165
+ name="John Smith",
166
+ )
167
+ ```
168
+
169
+ ### Shopify
170
+
171
+ `domain` is the store's domain, without `https://` or `www.`.
172
+
173
+ ```python
174
+ session_id = ccencrypt.ccshopify(
175
+ domain="example.com.au",
176
+ card="4242424242424242",
177
+ month="12",
178
+ year="2029",
179
+ cvv="123",
180
+ name="John Smith",
181
+ )
182
+ ```
183
+
184
+ The returned id goes into the checkout's payment as the card `sessionId`.
185
+
186
+ ### PayDock
187
+
188
+ `public_key` is the site's PayDock public key, sent as `x-user-public-key` in the site's requests to `api.paydock.com`.
189
+
190
+ ```python
191
+ token = ccencrypt.ccpaydock(
192
+ public_key="5b12b8af...",
193
+ card="4242424242424242",
194
+ month="12",
195
+ year="2029",
196
+ cvv="123",
197
+ name="John Smith",
198
+ )
199
+ ```
200
+
201
+ If the site's token request includes a `gateway_id`, pass it as `gateway_id`.
@@ -0,0 +1,25 @@
1
+ from ccencrypt.adyen import ccadyen, ccadyen_cse
2
+ from ccencrypt.adyen_cse import CSE_VERSIONS, cse_encrypt
3
+ from ccencrypt.braintree import ccbraintree
4
+ from ccencrypt.cybersource import CardTypes, card_type, cccybersource, cccybersource_token
5
+ from ccencrypt.eway import cceway, cceway_card
6
+ from ccencrypt.paydock import ccpaydock
7
+ from ccencrypt.shopify import ccshopify
8
+ from ccencrypt.stripe import ccstripe
9
+
10
+ __all__ = [
11
+ "ccadyen",
12
+ "ccadyen_cse",
13
+ "cse_encrypt",
14
+ "CSE_VERSIONS",
15
+ "cccybersource",
16
+ "cccybersource_token",
17
+ "cceway",
18
+ "cceway_card",
19
+ "ccstripe",
20
+ "ccbraintree",
21
+ "ccshopify",
22
+ "ccpaydock",
23
+ "CardTypes",
24
+ "card_type",
25
+ ]
@@ -0,0 +1,154 @@
1
+ import base64
2
+ import json
3
+ import os
4
+ from datetime import datetime, timezone
5
+
6
+ from cryptography.hazmat.backends import default_backend
7
+ from cryptography.hazmat.primitives import hashes, hmac
8
+ from cryptography.hazmat.primitives.asymmetric import padding, rsa
9
+ from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
10
+
11
+ from ccencrypt.adyen_cse import cse_encrypt
12
+ from ccencrypt.helpers.card import clean_card, expiry
13
+ from ccencrypt.helpers.encoding import b64url, hex_to_bytes, pack_bit_length
14
+
15
+ OAEP = padding.OAEP(
16
+ mgf=padding.MGF1(algorithm=hashes.SHA1()),
17
+ algorithm=hashes.SHA1(),
18
+ label=None,
19
+ )
20
+
21
+
22
+ def utc_stamp():
23
+ dt = datetime.now(timezone.utc)
24
+ return dt.strftime("%Y-%m-%dT%H:%M:%S.") + f"{int(dt.microsecond / 1000):03d}Z"
25
+
26
+
27
+ def parse_public_key(encrypt_key):
28
+ parts = encrypt_key.split("|", 1)
29
+ if len(parts) != 2:
30
+ raise ValueError("malformed encrypt key")
31
+ e = int.from_bytes(hex_to_bytes(parts[0]), "big")
32
+ n = int.from_bytes(hex_to_bytes(parts[1]), "big")
33
+ return rsa.RSAPublicNumbers(e, n).public_key(default_backend())
34
+
35
+
36
+ def jwe_encrypt(payload, public_key):
37
+ dek = os.urandom(64)
38
+ wrapped_key = public_key.encrypt(dek, OAEP)
39
+
40
+ header_json = json.dumps(
41
+ {"alg": "RSA-OAEP", "enc": "A256CBC-HS512", "version": "1"},
42
+ separators=(",", ":"),
43
+ )
44
+ header_b64 = b64url(header_json.encode("utf-8"))
45
+ header_raw = header_b64.encode("utf-8")
46
+
47
+ iv = os.urandom(16)
48
+ body = json.dumps(payload, separators=(",", ":")).encode("utf-8")
49
+ pad = 16 - (len(body) % 16)
50
+ body = body + bytes([pad]) * pad
51
+
52
+ enc = Cipher(algorithms.AES(dek[32:]), modes.CBC(iv), backend=default_backend()).encryptor()
53
+ ciphertext = enc.update(body) + enc.finalize()
54
+
55
+ mac = hmac.HMAC(dek[:32], hashes.SHA512(), backend=default_backend())
56
+ mac.update(header_raw + iv + ciphertext + pack_bit_length(len(header_raw)))
57
+ auth_tag = mac.finalize()[:32]
58
+
59
+ return ".".join([header_b64, b64url(wrapped_key), b64url(iv), b64url(ciphertext), b64url(auth_tag)])
60
+
61
+
62
+ def secured_fields_referrer(client_key, domain):
63
+ d = base64.b64encode(domain.encode("utf-8")).decode("ascii")
64
+ return (
65
+ "https://checkoutshopper-live.adyen.com/checkoutshopper/securedfields/"
66
+ f"{client_key}/4.5.0/securedFields.html?type=card&d={d}"
67
+ )
68
+
69
+
70
+ def format_pan(card):
71
+ digits = clean_card(card)
72
+ return " ".join(digits[i : i + 4] for i in range(0, len(digits), 4))
73
+
74
+
75
+ def build_card_payloads(card, month, year, cvc, referrer, ts):
76
+ pan = format_pan(card)
77
+ month, year = expiry(month, year)
78
+ cvc = str(cvc)
79
+ return {
80
+ "encryptedCardNumber": {
81
+ "number": pan,
82
+ "generationtime": ts,
83
+ "numberBind": "1",
84
+ "activate": "3",
85
+ "referrer": referrer,
86
+ "numberFieldFocusCount": "3",
87
+ "numberFieldLog": "fo@44070,cl@44071,KN@44082,fo@44324,cl@44325,cl@44333,KN@44346,KN@44347,KN@44348,KN@44350,KN@44351,KN@44353,KN@44354,KN@44355,KN@44356,KN@44358,fo@44431,cl@44432,KN@44434,KN@44436,KN@44438,KN@44440,KN@44440",
88
+ "numberFieldClickCount": "4",
89
+ "numberFieldKeyCount": "16",
90
+ },
91
+ "encryptedExpiryMonth": {"expiryMonth": month, "generationtime": ts},
92
+ "encryptedExpiryYear": {"expiryYear": year, "generationtime": ts},
93
+ "encryptedSecurityCode": {
94
+ "cvc": cvc,
95
+ "generationtime": ts,
96
+ "cvcBind": "1",
97
+ "activate": "4",
98
+ "referrer": referrer,
99
+ "cvcFieldFocusCount": "4",
100
+ "cvcFieldLog": "fo@122,cl@123,KN@136,KN@138,KN@140,fo@11204,cl@11205,ch@11221,bl@11221,fo@33384,bl@33384,fo@50318,cl@50319,cl@50321,KN@50334,KN@50336,KN@50336",
101
+ "cvcFieldClickCount": "4",
102
+ "cvcFieldKeyCount": "6",
103
+ "cvcFieldChangeCount": "1",
104
+ "cvcFieldBlurCount": "2",
105
+ "deactivate": "2",
106
+ },
107
+ }
108
+
109
+
110
+ def ccadyen(
111
+ encrypt_key,
112
+ card,
113
+ month,
114
+ year,
115
+ cvc,
116
+ client_key=None,
117
+ domain=None,
118
+ version="4.5.0",
119
+ ):
120
+ if not card or not month or not year or not cvc:
121
+ raise ValueError("missing card details")
122
+ if not encrypt_key:
123
+ raise ValueError("missing encrypt key")
124
+ if str(version).strip() != "4.5.0":
125
+ return ccadyen_cse(encrypt_key, card, month, year, cvc, version=version)
126
+ if not client_key:
127
+ client_key = "live_SQV7J3WVMNFK3HU33BTUNF5AH4E2L2ZN"
128
+ if not domain:
129
+ domain = "https://minisoshop.co.uk"
130
+
131
+ rsa_key = parse_public_key(encrypt_key)
132
+ referrer = secured_fields_referrer(client_key, domain)
133
+ ts = utc_stamp()
134
+ fields = build_card_payloads(card, month, year, cvc, referrer, ts)
135
+
136
+ return {name: jwe_encrypt(data, rsa_key) for name, data in fields.items()}
137
+
138
+
139
+ def ccadyen_cse(encrypt_key, card, month, year, cvc, version="0_1_25"):
140
+ if not card or not month or not year or not cvc:
141
+ raise ValueError("missing card details")
142
+ if not encrypt_key:
143
+ raise ValueError("missing encrypt key")
144
+
145
+ rsa_key = parse_public_key(encrypt_key)
146
+ ts = utc_stamp()
147
+ month, year = expiry(month, year)
148
+ fields = {
149
+ "encryptedCardNumber": {"number": format_pan(card), "generationtime": ts},
150
+ "encryptedExpiryMonth": {"expiryMonth": month, "generationtime": ts},
151
+ "encryptedExpiryYear": {"expiryYear": year, "generationtime": ts},
152
+ "encryptedSecurityCode": {"cvc": str(cvc), "generationtime": ts},
153
+ }
154
+ return {name: cse_encrypt(data, rsa_key, version) for name, data in fields.items()}
@@ -0,0 +1,45 @@
1
+ import base64
2
+ import json
3
+ import os
4
+
5
+ from cryptography.hazmat.primitives.asymmetric import padding
6
+ from cryptography.hazmat.primitives.ciphers.aead import AESCCM
7
+
8
+ CSE_VERSIONS = ("0_1_18", "0_1_22", "0_1_23", "0_1_24", "0_1_25")
9
+
10
+
11
+ def normalize_cse_version(version):
12
+ v = str(version).strip().lower().replace("adyenjs_", "").replace(".", "_")
13
+ if v.isdigit():
14
+ v = f"0_1_{v}"
15
+ if v not in CSE_VERSIONS:
16
+ raise ValueError(f"unsupported adyen cse version: {version!r}")
17
+ return v
18
+
19
+
20
+ def cse_extra_fields(version):
21
+ # Fields the adyen-encrypt JS lib appends to every payload for this version.
22
+ if version == "0_1_18":
23
+ return {"initializeCount": "1", "dfValue": ""}
24
+ if version == "0_1_25":
25
+ return {"initializeCount": "1", "sjclStrength": "10"}
26
+ return {"initializeCount": "1", "sjclStrength": "10", "dfValue": ""}
27
+
28
+
29
+ def cse_encrypt(data, public_key, version="0_1_25"):
30
+ version = normalize_cse_version(version)
31
+ payload = dict(data)
32
+ payload.update(cse_extra_fields(version))
33
+ plaintext = json.dumps(payload, separators=(",", ":")).encode("utf-8")
34
+
35
+ aes_key = os.urandom(32)
36
+ iv = os.urandom(12)
37
+ cipher = AESCCM(aes_key, tag_length=8).encrypt(iv, plaintext, None)
38
+ wrapped_key = public_key.encrypt(aes_key, padding.PKCS1v15())
39
+
40
+ return "".join([
41
+ f"adyenjs_{version}$",
42
+ base64.b64encode(wrapped_key).decode("ascii"),
43
+ "$",
44
+ base64.b64encode(iv + cipher).decode("ascii"),
45
+ ])
@@ -0,0 +1,66 @@
1
+ import base64
2
+ import json
3
+ import uuid
4
+
5
+ import requests
6
+
7
+ from ccencrypt.helpers.card import clean_card, expiry, proxies
8
+
9
+ BRAINTREE_GQL_URL = "https://payments.braintree-api.com/graphql"
10
+
11
+ TOKENIZE_QUERY = (
12
+ "mutation TokenizeCreditCard($input: TokenizeCreditCardInput!) { "
13
+ "tokenizeCreditCard(input: $input) { token creditCard { bin brandCode last4 } } }"
14
+ )
15
+
16
+
17
+ def fingerprint(client_token):
18
+ try:
19
+ data = json.loads(base64.b64decode(client_token))
20
+ except Exception:
21
+ return client_token
22
+ return data["authorizationFingerprint"]
23
+
24
+
25
+ def ccbraintree(client_token, card, month, year, cvv, name="", proxy=None, timeout=30):
26
+ month, year = expiry(month, year)
27
+ payload = {
28
+ "clientSdkMetadata": {
29
+ "source": "client",
30
+ "integration": "custom",
31
+ "sessionId": str(uuid.uuid4()),
32
+ },
33
+ "query": TOKENIZE_QUERY,
34
+ "variables": {
35
+ "input": {
36
+ "creditCard": {
37
+ "number": clean_card(card),
38
+ "expirationMonth": month,
39
+ "expirationYear": year,
40
+ "cvv": str(cvv).strip(),
41
+ "cardholderName": name,
42
+ },
43
+ "options": {"validate": False},
44
+ }
45
+ },
46
+ "operationName": "TokenizeCreditCard",
47
+ }
48
+
49
+ resp = requests.post(
50
+ BRAINTREE_GQL_URL,
51
+ headers={
52
+ "authorization": f"Bearer {fingerprint(client_token)}",
53
+ "braintree-version": "2018-05-10",
54
+ "content-type": "application/json",
55
+ "origin": "https://assets.braintreegateway.com",
56
+ "referer": "https://assets.braintreegateway.com/",
57
+ },
58
+ json=payload,
59
+ proxies=proxies(proxy),
60
+ timeout=timeout,
61
+ )
62
+ body = resp.json() if resp.text else {}
63
+ token = ((body.get("data") or {}).get("tokenizeCreditCard") or {}).get("token")
64
+ if resp.status_code != 200 or not token:
65
+ raise RuntimeError(f"braintree failed: {resp.status_code} {resp.text[:300]}")
66
+ return token
@@ -0,0 +1,150 @@
1
+ import json
2
+ import os
3
+ import urllib.parse
4
+
5
+ import requests
6
+
7
+ from cryptography.hazmat.backends import default_backend
8
+ from cryptography.hazmat.primitives import hashes
9
+ from cryptography.hazmat.primitives.asymmetric import padding, rsa
10
+ from cryptography.hazmat.primitives.ciphers.aead import AESGCM
11
+
12
+ from ccencrypt.helpers.card import clean_card, expiry, proxies
13
+ from ccencrypt.helpers.encoding import b64url, b64url_decode, jwt_payload
14
+
15
+ FLEX_TOKENS_URL = "https://flex.cybersource.com/flex/v2/tokens"
16
+
17
+
18
+ CardTypes = {
19
+ "Visa": "001",
20
+ "MasterCard": "002",
21
+ "AmericanExpress": "003",
22
+ "Discover": "004",
23
+ "Diners": "005",
24
+ "JCB": "007",
25
+ "Maestro": "042",
26
+ "ChinaUnionPay": "062",
27
+ }
28
+
29
+
30
+ def card_type(number):
31
+ n = clean_card(number)
32
+ if n.startswith("5"):
33
+ return CardTypes["MasterCard"]
34
+ if n.startswith("34") or n.startswith("37"):
35
+ return CardTypes["AmericanExpress"]
36
+ return CardTypes["Visa"]
37
+
38
+
39
+ def jwk_rsa_key(jwk):
40
+ e = int.from_bytes(b64url_decode(jwk["e"]), "big")
41
+ n = int.from_bytes(b64url_decode(jwk["n"]), "big")
42
+ return rsa.RSAPublicNumbers(e, n).public_key(default_backend())
43
+
44
+
45
+ def cccybersource(card, month, year, cvv, context, index=0):
46
+ key_id = jwt_payload(context)
47
+ jwk = key_id["flx"]["jwk"]
48
+ header = {
49
+ "kid": jwk["kid"],
50
+ "alg": "RSA-OAEP",
51
+ "enc": "A256GCM",
52
+ }
53
+ month, year = expiry(month, year)
54
+ payload = {
55
+ "data": {
56
+ "number": clean_card(card),
57
+ "securityCode": str(cvv),
58
+ "expirationMonth": month,
59
+ "expirationYear": year,
60
+ "type": card_type(card),
61
+ },
62
+ "context": context,
63
+ "index": index,
64
+ }
65
+
66
+ iv = os.urandom(12)
67
+ aes_key = AESGCM.generate_key(bit_length=256)
68
+ header_b64 = b64url(json.dumps(header, separators=(",", ":")))
69
+ aad = header_b64.encode("utf-8")
70
+ plaintext = json.dumps(payload, separators=(",", ":")).encode("utf-8")
71
+ encrypted = AESGCM(aes_key).encrypt(iv, plaintext, aad)
72
+
73
+ tag_len = 16
74
+ body = encrypted[:-tag_len]
75
+ tag = encrypted[-tag_len:]
76
+
77
+ wrapped = jwk_rsa_key(jwk).encrypt(
78
+ aes_key,
79
+ padding.OAEP(
80
+ mgf=padding.MGF1(algorithm=hashes.SHA1()),
81
+ algorithm=hashes.SHA1(),
82
+ label=None,
83
+ ),
84
+ )
85
+
86
+ return ".".join(
87
+ [
88
+ header_b64,
89
+ b64url(wrapped),
90
+ b64url(iv),
91
+ b64url(body),
92
+ b64url(tag),
93
+ ]
94
+ )
95
+
96
+
97
+ def microform_referer(context):
98
+ kid = jwt_payload(context)["flx"]["jwk"]["kid"]
99
+ q = urllib.parse.quote(kid, safe="")
100
+ return f"https://flex.cybersource.com/microform/bundle/v2.9.0/iframe.html?keyId={q}"
101
+
102
+
103
+ def cccybersource_token(
104
+ card,
105
+ month,
106
+ year,
107
+ cvv,
108
+ context,
109
+ origin=None,
110
+ referer=None,
111
+ user_agent=None,
112
+ microform=False,
113
+ index=0,
114
+ proxy=None,
115
+ timeout=30,
116
+ ):
117
+ encrypted = cccybersource(card, month, year, cvv, context, index=index)
118
+
119
+ if microform:
120
+ headers = {
121
+ "content-type": "application/jwt; charset=UTF-8",
122
+ "origin": "https://flex.cybersource.com",
123
+ "referer": referer or microform_referer(context),
124
+ }
125
+ else:
126
+ if not origin:
127
+ raise ValueError("origin required unless microform=True")
128
+ site = origin.rstrip("/")
129
+ headers = {
130
+ "content-type": "application/jwt",
131
+ "origin": site,
132
+ "referer": referer or f"{site}/",
133
+ }
134
+
135
+ if user_agent:
136
+ headers["user-agent"] = user_agent
137
+
138
+ resp = requests.post(
139
+ FLEX_TOKENS_URL,
140
+ headers=headers,
141
+ data=str(encrypted).strip(),
142
+ proxies=proxies(proxy),
143
+ timeout=timeout,
144
+ )
145
+ if resp.status_code != 201:
146
+ raise RuntimeError(f"flex /tokens failed: {resp.status_code} {(resp.text or '')[:300]}")
147
+ token = (resp.text or "").strip()
148
+ if not token:
149
+ raise RuntimeError("flex /tokens returned empty body")
150
+ return token
@@ -0,0 +1,35 @@
1
+ import base64
2
+
3
+ from cryptography.hazmat.backends import default_backend
4
+ from cryptography.hazmat.primitives.asymmetric import padding, rsa
5
+
6
+ from ccencrypt.helpers.card import clean_card
7
+
8
+
9
+ def modulus_from_key_blob(key_blob):
10
+ try:
11
+ mod_bytes = base64.b64decode(key_blob)
12
+ except Exception as exc:
13
+ raise ValueError("invalid encrypt key") from exc
14
+ n = int.from_bytes(mod_bytes, "big")
15
+ return rsa.RSAPublicNumbers(65537, n).public_key(default_backend())
16
+
17
+
18
+ def cceway(encrypt_key, value):
19
+ if not encrypt_key:
20
+ raise ValueError("missing encrypt key")
21
+ if value is None or str(value).strip() == "":
22
+ raise ValueError("missing value")
23
+
24
+ pub = modulus_from_key_blob(str(encrypt_key).strip())
25
+ ciphertext = pub.encrypt(str(value).encode("utf-8"), padding.PKCS1v15())
26
+ return "eCrypted:" + base64.b64encode(ciphertext).decode("ascii")
27
+
28
+
29
+ def cceway_card(encrypt_key, card, cvv):
30
+ pan = clean_card(card)
31
+ code = str(cvv).strip()
32
+ return {
33
+ "EWAY_CARDNUMBER": cceway(encrypt_key, pan),
34
+ "EWAY_CARDCVN": cceway(encrypt_key, code),
35
+ }
File without changes
@@ -0,0 +1,21 @@
1
+ def clean_card(card):
2
+ return str(card).strip().replace(" ", "").replace("-", "")
3
+
4
+
5
+ def spaced_card(card):
6
+ n = clean_card(card)
7
+ if len(n) == 15:
8
+ return f"{n[:4]} {n[4:10]} {n[10:]}"
9
+ return " ".join(n[i : i + 4] for i in range(0, len(n), 4))
10
+
11
+
12
+ def proxies(proxy):
13
+ return {"http": proxy, "https": proxy} if proxy else None
14
+
15
+
16
+ def expiry(month, year):
17
+ m = "".join(c for c in str(month) if c.isdigit()).zfill(2)[-2:]
18
+ y = "".join(c for c in str(year) if c.isdigit())
19
+ if len(y) == 2:
20
+ y = "20" + y
21
+ return m, y
@@ -0,0 +1,34 @@
1
+ import base64
2
+ import json
3
+
4
+
5
+ def b64url(data):
6
+ if isinstance(data, str):
7
+ data = data.encode("utf-8")
8
+ return base64.b64encode(data).decode("ascii").rstrip("=").replace("+", "-").replace("/", "_")
9
+
10
+
11
+ def hex_to_bytes(hex_str):
12
+ if not hex_str:
13
+ return b""
14
+ if len(hex_str) % 2 == 1:
15
+ hex_str = "0" + hex_str
16
+ return bytes.fromhex(hex_str)
17
+
18
+
19
+ def b64url_decode(s):
20
+ s = s.replace("-", "+").replace("_", "/")
21
+ pad = "=" * ((4 - len(s) % 4) % 4)
22
+ return base64.b64decode(s + pad)
23
+
24
+
25
+ def jwt_payload(token):
26
+ part = token.split(".")[1]
27
+ return json.loads(b64url_decode(part))
28
+
29
+
30
+ def pack_bit_length(length_bytes):
31
+ bits = length_bytes * 8
32
+ hi = bits // (2**32)
33
+ lo = bits % (2**32)
34
+ return hi.to_bytes(4, "big") + lo.to_bytes(4, "big")
@@ -0,0 +1,41 @@
1
+ import requests
2
+
3
+ from ccencrypt.helpers.card import clean_card, expiry, proxies
4
+
5
+ PAYDOCK_TOKENS_URL = "https://api.paydock.com/v1/payment_sources/tokens"
6
+
7
+
8
+ def ccpaydock(public_key, card, month, year, cvv, name, gateway_id="", proxy=None, timeout=30):
9
+ month, year = expiry(month, year)
10
+ payload = {
11
+ "type": "card",
12
+ "card_name": name,
13
+ "card_number": clean_card(card),
14
+ "expire_month": month,
15
+ "expire_year": year[-2:],
16
+ "card_ccv": str(cvv).strip(),
17
+ "gateway_id": gateway_id,
18
+ "store_ccv": True,
19
+ "meta": {},
20
+ }
21
+
22
+ resp = requests.post(
23
+ PAYDOCK_TOKENS_URL,
24
+ headers={
25
+ "accept": "application/json, text/plain, */*",
26
+ "content-type": "application/json",
27
+ "origin": "https://widget.paydock.com",
28
+ "referer": "https://widget.paydock.com/",
29
+ "x-sdk-type": "client",
30
+ "x-sdk-version": "v1.131.0",
31
+ "x-user-public-key": public_key,
32
+ },
33
+ json=payload,
34
+ proxies=proxies(proxy),
35
+ timeout=timeout,
36
+ )
37
+ body = resp.json() if resp.text else {}
38
+ token = (body.get("resource") or {}).get("data")
39
+ if resp.status_code != 201 or not token:
40
+ raise RuntimeError(f"paydock failed: {resp.status_code} {resp.text[:300]}")
41
+ return token
@@ -0,0 +1,40 @@
1
+ import requests
2
+
3
+ from ccencrypt.helpers.card import expiry, proxies, spaced_card
4
+
5
+ SHOPIFY_PCI_URL = "https://checkout.pci.shopifyinc.com/sessions"
6
+
7
+
8
+ def ccshopify(domain, card, month, year, cvv, name, proxy=None, timeout=30):
9
+ month, year = expiry(month, year)
10
+ payload = {
11
+ "credit_card": {
12
+ "number": spaced_card(card),
13
+ "month": int(month),
14
+ "year": int(year),
15
+ "verification_value": str(cvv).strip(),
16
+ "start_month": None,
17
+ "start_year": None,
18
+ "issue_number": "",
19
+ "name": name,
20
+ },
21
+ "payment_session_scope": domain.replace("https://", "").replace("www.", "").strip("/"),
22
+ }
23
+
24
+ resp = requests.post(
25
+ SHOPIFY_PCI_URL,
26
+ headers={
27
+ "accept": "application/json",
28
+ "content-type": "application/json",
29
+ "origin": "https://checkout.pci.shopifyinc.com",
30
+ "referer": "https://checkout.pci.shopifyinc.com/",
31
+ },
32
+ json=payload,
33
+ proxies=proxies(proxy),
34
+ timeout=timeout,
35
+ )
36
+ body = resp.json() if resp.text else {}
37
+ session_id = body.get("id")
38
+ if resp.status_code != 200 or not session_id:
39
+ raise RuntimeError(f"shopify failed: {resp.status_code} {resp.text[:300]}")
40
+ return session_id
@@ -0,0 +1,47 @@
1
+ import uuid
2
+
3
+ import requests
4
+
5
+ from ccencrypt.helpers.card import clean_card, expiry, proxies
6
+
7
+ STRIPE_PM_URL = "https://api.stripe.com/v1/payment_methods"
8
+ STRIPE_JS = "stripe.js/e2a5fc9c3e; stripe-js-v3/e2a5fc9c3e; card-element"
9
+
10
+
11
+ def ccstripe(key, card, month, year, cvc, name="", account=None, proxy=None, timeout=30):
12
+ month, year = expiry(month, year)
13
+ data = {
14
+ "type": "card",
15
+ "card[number]": clean_card(card),
16
+ "card[cvc]": str(cvc).strip(),
17
+ "card[exp_month]": month,
18
+ "card[exp_year]": year[-2:],
19
+ "payment_user_agent": STRIPE_JS,
20
+ "guid": str(uuid.uuid4()),
21
+ "muid": str(uuid.uuid4()),
22
+ "sid": str(uuid.uuid4()),
23
+ "key": key,
24
+ }
25
+ if name:
26
+ data["billing_details[name]"] = name
27
+ if account:
28
+ data["_stripe_account"] = account
29
+
30
+ resp = requests.post(
31
+ STRIPE_PM_URL,
32
+ headers={
33
+ "accept": "application/json",
34
+ "content-type": "application/x-www-form-urlencoded",
35
+ "origin": "https://js.stripe.com",
36
+ "referer": "https://js.stripe.com/",
37
+ },
38
+ data=data,
39
+ proxies=proxies(proxy),
40
+ timeout=timeout,
41
+ )
42
+ body = resp.json() if resp.text else {}
43
+ pm = body.get("id", "")
44
+ if resp.status_code != 200 or not pm.startswith("pm_"):
45
+ err = body.get("error") or {}
46
+ raise RuntimeError(f"stripe failed: {resp.status_code} {err.get('message') or resp.text[:300]}")
47
+ return pm
@@ -0,0 +1,24 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "CCencrypt"
7
+ version = "0.3.0"
8
+ description = "Card encryption and tokenisation for Adyen, CyberSource, eWay, Stripe, Braintree, Shopify and PayDock"
9
+ readme = "README.md"
10
+ requires-python = ">=3.9"
11
+ license = { text = "MIT" }
12
+ authors = [{ name = "itsregza" }]
13
+ dependencies = [
14
+ "cryptography>=42.0.0",
15
+ "requests>=2.28.0",
16
+ ]
17
+
18
+ [project.urls]
19
+ Homepage = "https://github.com/itsregza/CCencrypt"
20
+ Repository = "https://github.com/itsregza/CCencrypt"
21
+
22
+ [tool.setuptools.packages.find]
23
+ where = ["."]
24
+ include = ["ccencrypt*"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+