generateApiKey 0.4.5__tar.gz → 0.4.8__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.
- {generateApiKey-0.4.5 → generateapikey-0.4.8}/PKG-INFO +97 -52
- generateApiKey-0.4.5/generateApiKey.egg-info/PKG-INFO → generateapikey-0.4.8/README.md +78 -65
- generateapikey-0.4.8/generateApiKey/__init__.py +173 -0
- generateapikey-0.4.8/generateApiKey/utils.py +82 -0
- generateapikey-0.4.8/generateApiKey.egg-info/PKG-INFO +187 -0
- {generateApiKey-0.4.5 → generateapikey-0.4.8}/generateApiKey.egg-info/SOURCES.txt +3 -1
- {generateApiKey-0.4.5 → generateapikey-0.4.8}/setup.py +7 -1
- generateapikey-0.4.8/tests/test_generate.py +97 -0
- generateApiKey-0.4.5/README.md +0 -124
- generateApiKey-0.4.5/generateApiKey/__init__.py +0 -58
- {generateApiKey-0.4.5 → generateapikey-0.4.8}/LICENSE +0 -0
- {generateApiKey-0.4.5 → generateapikey-0.4.8}/MANIFEST.in +0 -0
- {generateApiKey-0.4.5 → generateapikey-0.4.8}/generateApiKey.egg-info/dependency_links.txt +0 -0
- {generateApiKey-0.4.5 → generateapikey-0.4.8}/generateApiKey.egg-info/requires.txt +0 -0
- {generateApiKey-0.4.5 → generateapikey-0.4.8}/generateApiKey.egg-info/top_level.txt +0 -0
- {generateApiKey-0.4.5 → generateapikey-0.4.8}/setup.cfg +0 -0
|
@@ -1,27 +1,42 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: generateApiKey
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.8
|
|
4
4
|
Summary: This package provides a convenient way to generate API keys using a secret, seed, and an optional include keyword. The generated keys are unique and secure, making them suitable for use in a variety of applications
|
|
5
5
|
Home-page: https://github.com/nuhmanpk/generate-api-key
|
|
6
6
|
Author: Nuhman Pk
|
|
7
7
|
Author-email: nuhmanpk7@gmail.com
|
|
8
8
|
License: MIT
|
|
9
|
-
|
|
9
|
+
Project-URL: Documentation, https://github.com/nuhmanpk/generate-api-key/blob/main/README.md
|
|
10
|
+
Project-URL: Funding, https://github.com/sponsors/nuhmanpk
|
|
11
|
+
Project-URL: Source, https://github.com/nuhmanpk/generate-api-key/
|
|
12
|
+
Project-URL: Tracker, https://github.com/nuhmanpk/generate-api-key/issues
|
|
10
13
|
Classifier: Programming Language :: Python :: 3.9
|
|
11
14
|
Classifier: License :: OSI Approved :: MIT License
|
|
12
15
|
Classifier: Operating System :: OS Independent
|
|
13
16
|
Requires-Python: >=3.9
|
|
14
17
|
Description-Content-Type: text/markdown
|
|
15
18
|
License-File: LICENSE
|
|
19
|
+
Requires-Dist: cryptography
|
|
20
|
+
Dynamic: author
|
|
21
|
+
Dynamic: author-email
|
|
22
|
+
Dynamic: classifier
|
|
23
|
+
Dynamic: description
|
|
24
|
+
Dynamic: description-content-type
|
|
25
|
+
Dynamic: home-page
|
|
26
|
+
Dynamic: license
|
|
27
|
+
Dynamic: license-file
|
|
28
|
+
Dynamic: project-url
|
|
29
|
+
Dynamic: requires-dist
|
|
30
|
+
Dynamic: requires-python
|
|
31
|
+
Dynamic: summary
|
|
16
32
|
|
|
17
33
|
[](https://pepy.tech/project/generateApiKey)
|
|
18
34
|
[](https://pypi.org/project/YoutubeTags)
|
|
19
35
|

|
|
20
36
|

|
|
21
|
-
[](https://generateApiKey.readthedocs.io/en/latest/?badge=latest)
|
|
22
37
|

|
|
23
38
|
[](https://pepy.tech/project/generateApiKey)
|
|
24
|
-
[](https://github.com/nuhmanpk/generate-api-key/actions/workflows/pypi-upload.yml)
|
|
25
40
|

|
|
26
41
|
# API Key Generation Package
|
|
27
42
|
|
|
@@ -56,77 +71,107 @@ To install your package, you can use the pip package manager by running the foll
|
|
|
56
71
|
pip install generateApiKey
|
|
57
72
|
```
|
|
58
73
|
|
|
59
|
-
#
|
|
60
|
-
|
|
74
|
+
# Quick start
|
|
75
|
+
|
|
76
|
+
The simplest way to get a secure key — no arguments, no `await`:
|
|
77
|
+
|
|
61
78
|
```python
|
|
62
|
-
from generateApiKey import
|
|
79
|
+
from generateApiKey import generate_api_key
|
|
80
|
+
|
|
81
|
+
api_key = generate_api_key() # 'uYTvAuzrTHAeU202ScbN6jV8kxIMogDf'
|
|
63
82
|
```
|
|
64
|
-
# Generating an API key
|
|
65
|
-
To generate an API key, you can use the generateApiKey() function and pass in the secret, seed, and an optional include keyword. For example:
|
|
66
83
|
|
|
67
|
-
|
|
68
|
-
|
|
84
|
+
That's it. Everything below is optional.
|
|
85
|
+
|
|
86
|
+
## Common recipes
|
|
69
87
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
88
|
+
```python
|
|
89
|
+
generate_api_key(length=48) # longer key
|
|
90
|
+
generate_api_key(prefix="sk") # 'sk-gRsNbb2lQ1cZxoT3...'
|
|
91
|
+
generate_api_key(dashes=True) # 'GdBA-6DhM-M3Fv-g99C...'
|
|
92
|
+
generate_api_key(charset="hex", length=32) # hex only
|
|
93
|
+
generate_api_key(charset="base58") # no ambiguous 0/O/I/l
|
|
94
|
+
generate_api_key(charset="ABC123", length=10) # your own alphabet
|
|
95
|
+
generate_api_key(case="upper", charset="alphabetic")
|
|
74
96
|
```
|
|
75
97
|
|
|
98
|
+
## Charsets
|
|
99
|
+
|
|
100
|
+
Pass a preset name or a literal string of characters to `charset`:
|
|
101
|
+
|
|
102
|
+
| Preset | Characters |
|
|
103
|
+
|--------|-----------|
|
|
104
|
+
| `alphanumeric` (default) | `A-Z a-z 0-9` |
|
|
105
|
+
| `base62` | `A-Z a-z 0-9` |
|
|
106
|
+
| `base58` | base62 minus `0 O I l` |
|
|
107
|
+
| `base64url` | `A-Z a-z 0-9 - _` |
|
|
108
|
+
| `alphabetic` | `A-Z a-z` |
|
|
109
|
+
| `numeric` | `0-9` |
|
|
110
|
+
| `hex` | `0-9 a-f` |
|
|
111
|
+
| `base16` | `0-9 A-F` |
|
|
112
|
+
|
|
113
|
+
## Expiring keys
|
|
114
|
+
|
|
115
|
+
Set `expiry` (minutes). The returned key **is a string** but also carries expiry metadata:
|
|
76
116
|
|
|
77
117
|
```python
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
118
|
+
key = generate_api_key(expiry=60)
|
|
119
|
+
|
|
120
|
+
headers = {"Authorization": key} # works — it's a str
|
|
121
|
+
key.expires_at # unix timestamp
|
|
122
|
+
key.is_expired # False (until 60 min pass)
|
|
81
123
|
```
|
|
82
124
|
|
|
125
|
+
## Derived keys (secret + seed)
|
|
126
|
+
|
|
127
|
+
Provide both `secret` and `seed` to derive the key deterministically from them
|
|
128
|
+
(HMAC-SHA256). A random salt still makes each generated key unique:
|
|
129
|
+
|
|
83
130
|
```python
|
|
84
|
-
|
|
85
|
-
api_key = generateApiKey(secret='Topsecret', seed='12',include='user1',add_dashes=True)
|
|
86
|
-
print(api_key)
|
|
131
|
+
generate_api_key("mysecret", "user-42", length=20, include="prod")
|
|
87
132
|
```
|
|
88
133
|
|
|
134
|
+
## Async is optional
|
|
135
|
+
|
|
136
|
+
The library is synchronous by default. When you need an awaitable:
|
|
89
137
|
|
|
90
138
|
```python
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
api_key = generateApiKey(secret, seed, include)
|
|
95
|
-
print(api_key)
|
|
139
|
+
from generateApiKey import generate_api_key_async
|
|
140
|
+
|
|
141
|
+
api_key = await generate_api_key_async(length=48, prefix="sk")
|
|
96
142
|
```
|
|
97
|
-
|
|
143
|
+
|
|
144
|
+
> The original `await generateApiKey(secret, seed, ...)` still works unchanged
|
|
145
|
+
> for backwards compatibility, but `generate_api_key` is recommended.
|
|
98
146
|
|
|
99
147
|
## Error handling
|
|
100
|
-
It is a good practice to handle errors, you can use the try and except block to handle any exception that may occur during the key generation process.
|
|
101
148
|
|
|
102
149
|
```python
|
|
103
150
|
try:
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
api_key = generateApiKey(secret, seed, include)
|
|
108
|
-
print(api_key)
|
|
109
|
-
except Exception as e:
|
|
110
|
-
print(e)
|
|
151
|
+
api_key = generate_api_key(length=32)
|
|
152
|
+
except ValueError as e:
|
|
153
|
+
print(e) # e.g. bad length, or only one of secret/seed given
|
|
111
154
|
```
|
|
112
155
|
|
|
113
|
-
|
|
156
|
+
# Parameters
|
|
114
157
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
158
|
+
All parameters are optional. Call `generate_api_key()` with nothing for a secure default.
|
|
159
|
+
|
|
160
|
+
| **Parameter** | **Type** | **Default** | **Description** |
|
|
161
|
+
|---------------|----------|-------------|-----------------|
|
|
162
|
+
| `secret` | `str` | `None` | Optional secret. Given with `seed`, the key is HMAC-derived instead of random. |
|
|
163
|
+
| `seed` | `str` | `None` | Optional per-key value, used together with `secret`. |
|
|
164
|
+
| `length` | `int` | `32` | Number of characters in the key body. |
|
|
165
|
+
| `charset` | `str` | `"alphanumeric"` | Preset name (see table) or a literal string of allowed characters. |
|
|
166
|
+
| `case` | `str` | `"mixed"` | `"mixed"`, `"lower"` or `"upper"`. Affects letters only. |
|
|
167
|
+
| `prefix` | `str` | `None` | Prefix joined with `separator`, e.g. `sk-...`. |
|
|
168
|
+
| `separator` | `str` | `"-"` | String between prefix and key. |
|
|
169
|
+
| `dashes` | `bool` | `False` | Group the key with dashes for readability. |
|
|
170
|
+
| `dash_group` | `int` | `4` | Group size when `dashes=True`. |
|
|
171
|
+
| `include` | `str` | `None` | Extra value mixed into a derived key (needs `secret` + `seed`). |
|
|
172
|
+
| `expiry` | `int` | `None` | Expiry in minutes; sets `.expires_at` / `.is_expired`. |
|
|
123
173
|
|
|
124
|
-
|
|
125
|
-
|----------|---------|-----------|--------------------|-------------|
|
|
126
|
-
| secret | `String` | Yes | "Topsecret" | The secret key used to generate the API key. It should be kept private and not shared with unauthorized parties. |
|
|
127
|
-
| seed | `String` | Yes | "12" | A value used to seed the generation of the API key. It can be any value, but it should be unique for each key. |
|
|
128
|
-
| include | `String` | Optional | "user1" | An optional value that can be included in the generated API key. It can be used to identify the user or application associated with the key. |
|
|
129
|
-
| add_dashes | `boolean` | Optional | True | A value used to determine wheather to add dashes or not in a key |
|
|
174
|
+
Returns an `ApiKey` — a `str` subclass, so it works anywhere a string does.
|
|
130
175
|
|
|
131
176
|
|
|
132
177
|
By using this package, you are solely liable for any legal issues that may arise from its unauthorized use or misuse, as well as any security risks that may result from not properly securing the secret key used to generate the API keys.
|
|
@@ -137,6 +182,6 @@ This package is provided as is, without any warranties or guarantees of any kind
|
|
|
137
182
|
|
|
138
183
|
We encourage you to use the package responsibly, and to report any security issues or bugs you may encounter.
|
|
139
184
|
|
|
140
|
-
[Nuhman Pk](https://github.com/nuhmanpk)
|
|
141
185
|
|
|
142
186
|
|
|
187
|
+
Made with ❤️ , **Happy coding! 🚀**
|
|
@@ -1,27 +1,10 @@
|
|
|
1
|
-
Metadata-Version: 2.1
|
|
2
|
-
Name: generateApiKey
|
|
3
|
-
Version: 0.4.5
|
|
4
|
-
Summary: This package provides a convenient way to generate API keys using a secret, seed, and an optional include keyword. The generated keys are unique and secure, making them suitable for use in a variety of applications
|
|
5
|
-
Home-page: https://github.com/nuhmanpk/generate-api-key
|
|
6
|
-
Author: Nuhman Pk
|
|
7
|
-
Author-email: nuhmanpk7@gmail.com
|
|
8
|
-
License: MIT
|
|
9
|
-
Platform: UNKNOWN
|
|
10
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
11
|
-
Classifier: License :: OSI Approved :: MIT License
|
|
12
|
-
Classifier: Operating System :: OS Independent
|
|
13
|
-
Requires-Python: >=3.9
|
|
14
|
-
Description-Content-Type: text/markdown
|
|
15
|
-
License-File: LICENSE
|
|
16
|
-
|
|
17
1
|
[](https://pepy.tech/project/generateApiKey)
|
|
18
2
|
[](https://pypi.org/project/YoutubeTags)
|
|
19
3
|

|
|
20
4
|

|
|
21
|
-
[](https://generateApiKey.readthedocs.io/en/latest/?badge=latest)
|
|
22
5
|

|
|
23
6
|
[](https://pepy.tech/project/generateApiKey)
|
|
24
|
-
[](https://github.com/nuhmanpk/generate-api-key/actions/workflows/pypi-upload.yml)
|
|
25
8
|

|
|
26
9
|
# API Key Generation Package
|
|
27
10
|
|
|
@@ -56,77 +39,107 @@ To install your package, you can use the pip package manager by running the foll
|
|
|
56
39
|
pip install generateApiKey
|
|
57
40
|
```
|
|
58
41
|
|
|
59
|
-
#
|
|
60
|
-
|
|
42
|
+
# Quick start
|
|
43
|
+
|
|
44
|
+
The simplest way to get a secure key — no arguments, no `await`:
|
|
45
|
+
|
|
61
46
|
```python
|
|
62
|
-
from generateApiKey import
|
|
47
|
+
from generateApiKey import generate_api_key
|
|
48
|
+
|
|
49
|
+
api_key = generate_api_key() # 'uYTvAuzrTHAeU202ScbN6jV8kxIMogDf'
|
|
63
50
|
```
|
|
64
|
-
# Generating an API key
|
|
65
|
-
To generate an API key, you can use the generateApiKey() function and pass in the secret, seed, and an optional include keyword. For example:
|
|
66
51
|
|
|
67
|
-
|
|
68
|
-
from generateApiKey import generateApiKey
|
|
52
|
+
That's it. Everything below is optional.
|
|
69
53
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
54
|
+
## Common recipes
|
|
55
|
+
|
|
56
|
+
```python
|
|
57
|
+
generate_api_key(length=48) # longer key
|
|
58
|
+
generate_api_key(prefix="sk") # 'sk-gRsNbb2lQ1cZxoT3...'
|
|
59
|
+
generate_api_key(dashes=True) # 'GdBA-6DhM-M3Fv-g99C...'
|
|
60
|
+
generate_api_key(charset="hex", length=32) # hex only
|
|
61
|
+
generate_api_key(charset="base58") # no ambiguous 0/O/I/l
|
|
62
|
+
generate_api_key(charset="ABC123", length=10) # your own alphabet
|
|
63
|
+
generate_api_key(case="upper", charset="alphabetic")
|
|
74
64
|
```
|
|
75
65
|
|
|
66
|
+
## Charsets
|
|
67
|
+
|
|
68
|
+
Pass a preset name or a literal string of characters to `charset`:
|
|
69
|
+
|
|
70
|
+
| Preset | Characters |
|
|
71
|
+
|--------|-----------|
|
|
72
|
+
| `alphanumeric` (default) | `A-Z a-z 0-9` |
|
|
73
|
+
| `base62` | `A-Z a-z 0-9` |
|
|
74
|
+
| `base58` | base62 minus `0 O I l` |
|
|
75
|
+
| `base64url` | `A-Z a-z 0-9 - _` |
|
|
76
|
+
| `alphabetic` | `A-Z a-z` |
|
|
77
|
+
| `numeric` | `0-9` |
|
|
78
|
+
| `hex` | `0-9 a-f` |
|
|
79
|
+
| `base16` | `0-9 A-F` |
|
|
80
|
+
|
|
81
|
+
## Expiring keys
|
|
82
|
+
|
|
83
|
+
Set `expiry` (minutes). The returned key **is a string** but also carries expiry metadata:
|
|
76
84
|
|
|
77
85
|
```python
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
86
|
+
key = generate_api_key(expiry=60)
|
|
87
|
+
|
|
88
|
+
headers = {"Authorization": key} # works — it's a str
|
|
89
|
+
key.expires_at # unix timestamp
|
|
90
|
+
key.is_expired # False (until 60 min pass)
|
|
81
91
|
```
|
|
82
92
|
|
|
93
|
+
## Derived keys (secret + seed)
|
|
94
|
+
|
|
95
|
+
Provide both `secret` and `seed` to derive the key deterministically from them
|
|
96
|
+
(HMAC-SHA256). A random salt still makes each generated key unique:
|
|
97
|
+
|
|
83
98
|
```python
|
|
84
|
-
|
|
85
|
-
api_key = generateApiKey(secret='Topsecret', seed='12',include='user1',add_dashes=True)
|
|
86
|
-
print(api_key)
|
|
99
|
+
generate_api_key("mysecret", "user-42", length=20, include="prod")
|
|
87
100
|
```
|
|
88
101
|
|
|
102
|
+
## Async is optional
|
|
103
|
+
|
|
104
|
+
The library is synchronous by default. When you need an awaitable:
|
|
89
105
|
|
|
90
106
|
```python
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
api_key = generateApiKey(secret, seed, include)
|
|
95
|
-
print(api_key)
|
|
107
|
+
from generateApiKey import generate_api_key_async
|
|
108
|
+
|
|
109
|
+
api_key = await generate_api_key_async(length=48, prefix="sk")
|
|
96
110
|
```
|
|
97
|
-
|
|
111
|
+
|
|
112
|
+
> The original `await generateApiKey(secret, seed, ...)` still works unchanged
|
|
113
|
+
> for backwards compatibility, but `generate_api_key` is recommended.
|
|
98
114
|
|
|
99
115
|
## Error handling
|
|
100
|
-
It is a good practice to handle errors, you can use the try and except block to handle any exception that may occur during the key generation process.
|
|
101
116
|
|
|
102
117
|
```python
|
|
103
118
|
try:
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
api_key = generateApiKey(secret, seed, include)
|
|
108
|
-
print(api_key)
|
|
109
|
-
except Exception as e:
|
|
110
|
-
print(e)
|
|
119
|
+
api_key = generate_api_key(length=32)
|
|
120
|
+
except ValueError as e:
|
|
121
|
+
print(e) # e.g. bad length, or only one of secret/seed given
|
|
111
122
|
```
|
|
112
123
|
|
|
113
|
-
|
|
124
|
+
# Parameters
|
|
114
125
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
126
|
+
All parameters are optional. Call `generate_api_key()` with nothing for a secure default.
|
|
127
|
+
|
|
128
|
+
| **Parameter** | **Type** | **Default** | **Description** |
|
|
129
|
+
|---------------|----------|-------------|-----------------|
|
|
130
|
+
| `secret` | `str` | `None` | Optional secret. Given with `seed`, the key is HMAC-derived instead of random. |
|
|
131
|
+
| `seed` | `str` | `None` | Optional per-key value, used together with `secret`. |
|
|
132
|
+
| `length` | `int` | `32` | Number of characters in the key body. |
|
|
133
|
+
| `charset` | `str` | `"alphanumeric"` | Preset name (see table) or a literal string of allowed characters. |
|
|
134
|
+
| `case` | `str` | `"mixed"` | `"mixed"`, `"lower"` or `"upper"`. Affects letters only. |
|
|
135
|
+
| `prefix` | `str` | `None` | Prefix joined with `separator`, e.g. `sk-...`. |
|
|
136
|
+
| `separator` | `str` | `"-"` | String between prefix and key. |
|
|
137
|
+
| `dashes` | `bool` | `False` | Group the key with dashes for readability. |
|
|
138
|
+
| `dash_group` | `int` | `4` | Group size when `dashes=True`. |
|
|
139
|
+
| `include` | `str` | `None` | Extra value mixed into a derived key (needs `secret` + `seed`). |
|
|
140
|
+
| `expiry` | `int` | `None` | Expiry in minutes; sets `.expires_at` / `.is_expired`. |
|
|
123
141
|
|
|
124
|
-
|
|
125
|
-
|----------|---------|-----------|--------------------|-------------|
|
|
126
|
-
| secret | `String` | Yes | "Topsecret" | The secret key used to generate the API key. It should be kept private and not shared with unauthorized parties. |
|
|
127
|
-
| seed | `String` | Yes | "12" | A value used to seed the generation of the API key. It can be any value, but it should be unique for each key. |
|
|
128
|
-
| include | `String` | Optional | "user1" | An optional value that can be included in the generated API key. It can be used to identify the user or application associated with the key. |
|
|
129
|
-
| add_dashes | `boolean` | Optional | True | A value used to determine wheather to add dashes or not in a key |
|
|
142
|
+
Returns an `ApiKey` — a `str` subclass, so it works anywhere a string does.
|
|
130
143
|
|
|
131
144
|
|
|
132
145
|
By using this package, you are solely liable for any legal issues that may arise from its unauthorized use or misuse, as well as any security risks that may result from not properly securing the secret key used to generate the API keys.
|
|
@@ -137,6 +150,6 @@ This package is provided as is, without any warranties or guarantees of any kind
|
|
|
137
150
|
|
|
138
151
|
We encourage you to use the package responsibly, and to report any security issues or bugs you may encounter.
|
|
139
152
|
|
|
140
|
-
[Nuhman Pk](https://github.com/nuhmanpk)
|
|
141
153
|
|
|
142
154
|
|
|
155
|
+
Made with ❤️ , **Happy coding! 🚀**
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
"""generateApiKey — simple, secure API key generation.
|
|
2
|
+
|
|
3
|
+
Quick start::
|
|
4
|
+
|
|
5
|
+
from generateApiKey import generate_api_key
|
|
6
|
+
|
|
7
|
+
key = generate_api_key() # secure random, 32 chars
|
|
8
|
+
key = generate_api_key(length=48, prefix="sk") # sk-xxxxxxxx...
|
|
9
|
+
key = generate_api_key(expiry=60) # expires in 60 minutes
|
|
10
|
+
|
|
11
|
+
Everything is synchronous by default. Use :func:`generate_api_key_async`
|
|
12
|
+
when you need an awaitable, or the legacy :func:`generateApiKey`.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
import time
|
|
16
|
+
|
|
17
|
+
from .utils import (
|
|
18
|
+
CHARSETS,
|
|
19
|
+
build_charset,
|
|
20
|
+
random_key,
|
|
21
|
+
derived_key,
|
|
22
|
+
add_dashes,
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
__all__ = [
|
|
26
|
+
"generate_api_key",
|
|
27
|
+
"generate_api_key_async",
|
|
28
|
+
"generateApiKey",
|
|
29
|
+
"ApiKey",
|
|
30
|
+
"is_expired",
|
|
31
|
+
"is_token_valid",
|
|
32
|
+
"CHARSETS",
|
|
33
|
+
]
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class ApiKey(str):
|
|
37
|
+
"""An API key.
|
|
38
|
+
|
|
39
|
+
Behaves exactly like a ``str`` (usable in headers, f-strings, comparisons)
|
|
40
|
+
while carrying optional expiry metadata::
|
|
41
|
+
|
|
42
|
+
key = generate_api_key(expiry=60)
|
|
43
|
+
headers = {"Authorization": key} # works, it's a str
|
|
44
|
+
key.expires_at # unix timestamp or None
|
|
45
|
+
key.is_expired # bool
|
|
46
|
+
"""
|
|
47
|
+
|
|
48
|
+
expires_at = None
|
|
49
|
+
|
|
50
|
+
def __new__(cls, value: str, expires_at: int = None) -> "ApiKey":
|
|
51
|
+
obj = super().__new__(cls, value)
|
|
52
|
+
obj.expires_at = expires_at
|
|
53
|
+
return obj
|
|
54
|
+
|
|
55
|
+
@property
|
|
56
|
+
def is_expired(self) -> bool:
|
|
57
|
+
"""True if an expiry was set and it is now in the past."""
|
|
58
|
+
return self.expires_at is not None and time.time() >= self.expires_at
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def generate_api_key(
|
|
62
|
+
secret: str = None,
|
|
63
|
+
seed: str = None,
|
|
64
|
+
*,
|
|
65
|
+
length: int = 32,
|
|
66
|
+
charset: str = "alphanumeric",
|
|
67
|
+
case: str = "mixed",
|
|
68
|
+
prefix: str = None,
|
|
69
|
+
separator: str = "-",
|
|
70
|
+
dashes: bool = False,
|
|
71
|
+
dash_group: int = 4,
|
|
72
|
+
include: str = None,
|
|
73
|
+
expiry: int = None,
|
|
74
|
+
) -> ApiKey:
|
|
75
|
+
"""Generate a secure API key.
|
|
76
|
+
|
|
77
|
+
With no arguments it returns a cryptographically random key. Pass both
|
|
78
|
+
``secret`` and ``seed`` to derive the key from them via HMAC-SHA256 instead.
|
|
79
|
+
|
|
80
|
+
Args:
|
|
81
|
+
secret: Optional secret. If given with ``seed``, the key is HMAC-derived.
|
|
82
|
+
seed: Optional per-key value used together with ``secret``.
|
|
83
|
+
length: Number of characters in the key body (before prefix/dashes). Default 32.
|
|
84
|
+
charset: A preset name (see ``CHARSETS``) or a literal string of allowed
|
|
85
|
+
characters. Presets: alphanumeric, base62, base58, base64url,
|
|
86
|
+
alphabetic, numeric, hex, base16.
|
|
87
|
+
case: ``"mixed"`` (default), ``"lower"`` or ``"upper"``.
|
|
88
|
+
prefix: Optional prefix, joined with ``separator`` (e.g. ``sk-...``).
|
|
89
|
+
separator: String used between prefix and key. Default ``"-"``.
|
|
90
|
+
dashes: If True, group the key body with dashes for readability.
|
|
91
|
+
dash_group: Group size when ``dashes`` is True. Default 4.
|
|
92
|
+
include: Extra value mixed into a derived key (requires secret + seed).
|
|
93
|
+
expiry: Optional expiry in minutes. Sets ``ApiKey.expires_at``.
|
|
94
|
+
|
|
95
|
+
Returns:
|
|
96
|
+
An :class:`ApiKey` (a ``str`` subclass).
|
|
97
|
+
|
|
98
|
+
Raises:
|
|
99
|
+
ValueError: If ``length`` < 1, or a bad ``charset``/``case`` is given, or
|
|
100
|
+
only one of ``secret``/``seed`` is supplied.
|
|
101
|
+
"""
|
|
102
|
+
if length < 1:
|
|
103
|
+
raise ValueError("length must be a positive integer.")
|
|
104
|
+
if (secret is None) != (seed is None):
|
|
105
|
+
raise ValueError("Provide both 'secret' and 'seed', or neither.")
|
|
106
|
+
|
|
107
|
+
chars = build_charset(charset, case)
|
|
108
|
+
|
|
109
|
+
if secret and seed:
|
|
110
|
+
body = derived_key(secret, seed, include, length, chars)
|
|
111
|
+
else:
|
|
112
|
+
body = random_key(length, chars)
|
|
113
|
+
|
|
114
|
+
if dashes:
|
|
115
|
+
body = add_dashes(body, dash_group)
|
|
116
|
+
|
|
117
|
+
key = f"{prefix}{separator}{body}" if prefix else body
|
|
118
|
+
|
|
119
|
+
expires_at = int(time.time()) + expiry * 60 if expiry else None
|
|
120
|
+
return ApiKey(key, expires_at)
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
async def generate_api_key_async(*args, **kwargs) -> ApiKey:
|
|
124
|
+
"""Async wrapper around :func:`generate_api_key` with the same signature."""
|
|
125
|
+
return generate_api_key(*args, **kwargs)
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
def is_expired(key: "ApiKey") -> bool:
|
|
129
|
+
"""Return True if ``key`` is an expired :class:`ApiKey`."""
|
|
130
|
+
return getattr(key, "is_expired", False)
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
# ---------------------------------------------------------------------------
|
|
134
|
+
# Backwards-compatible legacy API (async). Prefer generate_api_key above.
|
|
135
|
+
# ---------------------------------------------------------------------------
|
|
136
|
+
|
|
137
|
+
async def generateApiKey(
|
|
138
|
+
secret: str,
|
|
139
|
+
seed: str,
|
|
140
|
+
include: str = None,
|
|
141
|
+
add_dashes: bool = False,
|
|
142
|
+
prefix: str = None,
|
|
143
|
+
length: int = None,
|
|
144
|
+
expiry: int = None,
|
|
145
|
+
) -> ApiKey:
|
|
146
|
+
"""Legacy async entry point. Kept for backwards compatibility.
|
|
147
|
+
|
|
148
|
+
New code should use :func:`generate_api_key` (synchronous, more options).
|
|
149
|
+
"""
|
|
150
|
+
if not secret or not seed:
|
|
151
|
+
raise ValueError("Secret and seed cannot be empty strings.")
|
|
152
|
+
|
|
153
|
+
return generate_api_key(
|
|
154
|
+
secret,
|
|
155
|
+
seed,
|
|
156
|
+
length=length or 32,
|
|
157
|
+
include=include,
|
|
158
|
+
prefix=prefix,
|
|
159
|
+
dashes=add_dashes,
|
|
160
|
+
dash_group=4,
|
|
161
|
+
expiry=expiry,
|
|
162
|
+
)
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
async def is_token_valid(token: str) -> bool:
|
|
166
|
+
"""Legacy check for the ``_<timestamp>`` expiry token format."""
|
|
167
|
+
if "_" not in token:
|
|
168
|
+
return False
|
|
169
|
+
try:
|
|
170
|
+
expiration_time = int(token.split("_")[1])
|
|
171
|
+
return int(time.time()) < expiration_time
|
|
172
|
+
except (IndexError, ValueError):
|
|
173
|
+
return False
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import hmac
|
|
2
|
+
import time
|
|
3
|
+
import hashlib
|
|
4
|
+
import string
|
|
5
|
+
from secrets import choice, token_bytes
|
|
6
|
+
|
|
7
|
+
# Named character sets available via the ``charset`` option.
|
|
8
|
+
CHARSETS = {
|
|
9
|
+
"alphanumeric": string.ascii_letters + string.digits,
|
|
10
|
+
"base62": string.ascii_letters + string.digits,
|
|
11
|
+
"alphabetic": string.ascii_letters,
|
|
12
|
+
"numeric": string.digits,
|
|
13
|
+
"hex": string.digits + "abcdef",
|
|
14
|
+
"base16": string.digits + "ABCDEF",
|
|
15
|
+
"base64url": string.ascii_letters + string.digits + "-_",
|
|
16
|
+
# base58 = base62 minus the ambiguous chars 0, O, I and l
|
|
17
|
+
"base58": "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz",
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def build_charset(charset: str, case: str) -> str:
|
|
22
|
+
"""Resolve a charset name (or a custom literal string) and apply a case rule.
|
|
23
|
+
|
|
24
|
+
Args:
|
|
25
|
+
charset: A named preset in ``CHARSETS`` or a literal string of characters.
|
|
26
|
+
case: One of ``"mixed"``, ``"lower"`` or ``"upper"``. Only affects letters.
|
|
27
|
+
|
|
28
|
+
Returns:
|
|
29
|
+
The final string of characters to draw from.
|
|
30
|
+
"""
|
|
31
|
+
chars = CHARSETS.get(charset, charset)
|
|
32
|
+
if not chars:
|
|
33
|
+
raise ValueError(f"Unknown or empty charset: {charset!r}")
|
|
34
|
+
|
|
35
|
+
if case == "lower":
|
|
36
|
+
chars = "".join(dict.fromkeys(chars.lower()))
|
|
37
|
+
elif case == "upper":
|
|
38
|
+
chars = "".join(dict.fromkeys(chars.upper()))
|
|
39
|
+
elif case != "mixed":
|
|
40
|
+
raise ValueError("case must be one of 'mixed', 'lower', 'upper'.")
|
|
41
|
+
return chars
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def random_key(length: int, chars: str) -> str:
|
|
45
|
+
"""Return a cryptographically secure random string of ``length`` from ``chars``."""
|
|
46
|
+
return "".join(choice(chars) for _ in range(length))
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def derived_key(secret: str, seed: str, include: str, length: int, chars: str) -> str:
|
|
50
|
+
"""Derive a key from ``secret``/``seed`` using HMAC-SHA256 as a byte stream.
|
|
51
|
+
|
|
52
|
+
A fresh random salt keeps every generated key unique even for identical
|
|
53
|
+
inputs. The HMAC output is mapped onto ``chars`` to honour the charset.
|
|
54
|
+
"""
|
|
55
|
+
salt = token_bytes(16)
|
|
56
|
+
message = f"{seed}{include or ''}{int(time.time())}".encode()
|
|
57
|
+
material = bytearray()
|
|
58
|
+
counter = 0
|
|
59
|
+
while len(material) < length:
|
|
60
|
+
block = hmac.new(
|
|
61
|
+
secret.encode(),
|
|
62
|
+
message + salt + counter.to_bytes(4, "big"),
|
|
63
|
+
hashlib.sha256,
|
|
64
|
+
).digest()
|
|
65
|
+
material.extend(block)
|
|
66
|
+
counter += 1
|
|
67
|
+
return "".join(chars[b % len(chars)] for b in material[:length])
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def add_dashes(key: str, group: int, sep: str = "-") -> str:
|
|
71
|
+
"""Insert ``sep`` every ``group`` characters, e.g. ``ABCD-EFGH-IJKL``."""
|
|
72
|
+
if group < 1:
|
|
73
|
+
return key
|
|
74
|
+
return sep.join(key[i : i + group] for i in range(0, len(key), group))
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def generate_expiration_token(minutes: int) -> str:
|
|
78
|
+
"""Return a stateless expiry token of the form ``_<unix_timestamp>``.
|
|
79
|
+
|
|
80
|
+
Kept for backwards compatibility with :func:`generateApiKey`.
|
|
81
|
+
"""
|
|
82
|
+
return f"_{int(time.time()) + minutes * 60}"
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: generateApiKey
|
|
3
|
+
Version: 0.4.8
|
|
4
|
+
Summary: This package provides a convenient way to generate API keys using a secret, seed, and an optional include keyword. The generated keys are unique and secure, making them suitable for use in a variety of applications
|
|
5
|
+
Home-page: https://github.com/nuhmanpk/generate-api-key
|
|
6
|
+
Author: Nuhman Pk
|
|
7
|
+
Author-email: nuhmanpk7@gmail.com
|
|
8
|
+
License: MIT
|
|
9
|
+
Project-URL: Documentation, https://github.com/nuhmanpk/generate-api-key/blob/main/README.md
|
|
10
|
+
Project-URL: Funding, https://github.com/sponsors/nuhmanpk
|
|
11
|
+
Project-URL: Source, https://github.com/nuhmanpk/generate-api-key/
|
|
12
|
+
Project-URL: Tracker, https://github.com/nuhmanpk/generate-api-key/issues
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Operating System :: OS Independent
|
|
16
|
+
Requires-Python: >=3.9
|
|
17
|
+
Description-Content-Type: text/markdown
|
|
18
|
+
License-File: LICENSE
|
|
19
|
+
Requires-Dist: cryptography
|
|
20
|
+
Dynamic: author
|
|
21
|
+
Dynamic: author-email
|
|
22
|
+
Dynamic: classifier
|
|
23
|
+
Dynamic: description
|
|
24
|
+
Dynamic: description-content-type
|
|
25
|
+
Dynamic: home-page
|
|
26
|
+
Dynamic: license
|
|
27
|
+
Dynamic: license-file
|
|
28
|
+
Dynamic: project-url
|
|
29
|
+
Dynamic: requires-dist
|
|
30
|
+
Dynamic: requires-python
|
|
31
|
+
Dynamic: summary
|
|
32
|
+
|
|
33
|
+
[](https://pepy.tech/project/generateApiKey)
|
|
34
|
+
[](https://pypi.org/project/YoutubeTags)
|
|
35
|
+

|
|
36
|
+

|
|
37
|
+

|
|
38
|
+
[](https://pepy.tech/project/generateApiKey)
|
|
39
|
+
[](https://github.com/nuhmanpk/generate-api-key/actions/workflows/pypi-upload.yml)
|
|
40
|
+

|
|
41
|
+
# API Key Generation Package
|
|
42
|
+
|
|
43
|
+
Timestamp and Numeric Representation: Now, the package incorporates a time-based and date-based hashing mechanism, adding an extra layer of security to your API keys. It captures the current timestamp and numeric representation of the key generation process, creating a unique identifier that's closely tied to the moment it was generated. This feature adds an element of time-based uniqueness to your keys, making them even more secure and less predictable.
|
|
44
|
+
|
|
45
|
+
This package provides a convenient way to generate API keys using a secret, seed, and an optional include keyword. The generated keys are unique and secure, making them suitable for use in a variety of applications.
|
|
46
|
+
|
|
47
|
+
The package supports generating API keys using a variety of methods such as UUID v5 and SHA-256 algorithm. The keys are generated using a combination of seed, secret, and include keyword. Additionally, the package allows you to insert the include keyword at a random position in the seed which will make it more difficult to guess.
|
|
48
|
+
|
|
49
|
+
It is important to keep the secret used to generate the keys secure and not share it with unauthorized parties. Additionally, the package can only be used for legitimate and legal purposes.
|
|
50
|
+
|
|
51
|
+
Please keep in mind that, even though this package provides a secure way to generate API keys, it is still important to use other security measures such as rate limiting, IP whitelisting, and encryption to protect your API and the data it accesses.
|
|
52
|
+
|
|
53
|
+
By using this package, you agree to take all necessary precautions to protect the data and resources accessed with the keys from unauthorized access or misuse. It is recommended to consult with a security expert before using this package or handling sensitive data.
|
|
54
|
+
|
|
55
|
+
# Privacy Policy
|
|
56
|
+
|
|
57
|
+
This package generates API keys that can be used to access sensitive data or resources. By using this package, you agree to keep the secret used to generate the keys secure and not share it with unauthorized parties. Additionally, the package can only be used for legitimate and legal purposes.
|
|
58
|
+
|
|
59
|
+
Please be aware that the package may cause a security risk if not used properly. The authors of this package cannot be held responsible for any unauthorized access or misuse of the keys generated by this package.
|
|
60
|
+
|
|
61
|
+
It is the user's responsibility to ensure the security of the keys and the protection of the data. It is recommended to consult with a security expert before using this package or handling sensitive data.
|
|
62
|
+
|
|
63
|
+
By using this package, you agree to take all necessary precautions to protect the data and resources accessed with the keys from unauthorized access or misuse.
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
# Installation
|
|
68
|
+
To install your package, you can use the pip package manager by running the following command in your command line:
|
|
69
|
+
|
|
70
|
+
```python
|
|
71
|
+
pip install generateApiKey
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
# Quick start
|
|
75
|
+
|
|
76
|
+
The simplest way to get a secure key — no arguments, no `await`:
|
|
77
|
+
|
|
78
|
+
```python
|
|
79
|
+
from generateApiKey import generate_api_key
|
|
80
|
+
|
|
81
|
+
api_key = generate_api_key() # 'uYTvAuzrTHAeU202ScbN6jV8kxIMogDf'
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
That's it. Everything below is optional.
|
|
85
|
+
|
|
86
|
+
## Common recipes
|
|
87
|
+
|
|
88
|
+
```python
|
|
89
|
+
generate_api_key(length=48) # longer key
|
|
90
|
+
generate_api_key(prefix="sk") # 'sk-gRsNbb2lQ1cZxoT3...'
|
|
91
|
+
generate_api_key(dashes=True) # 'GdBA-6DhM-M3Fv-g99C...'
|
|
92
|
+
generate_api_key(charset="hex", length=32) # hex only
|
|
93
|
+
generate_api_key(charset="base58") # no ambiguous 0/O/I/l
|
|
94
|
+
generate_api_key(charset="ABC123", length=10) # your own alphabet
|
|
95
|
+
generate_api_key(case="upper", charset="alphabetic")
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## Charsets
|
|
99
|
+
|
|
100
|
+
Pass a preset name or a literal string of characters to `charset`:
|
|
101
|
+
|
|
102
|
+
| Preset | Characters |
|
|
103
|
+
|--------|-----------|
|
|
104
|
+
| `alphanumeric` (default) | `A-Z a-z 0-9` |
|
|
105
|
+
| `base62` | `A-Z a-z 0-9` |
|
|
106
|
+
| `base58` | base62 minus `0 O I l` |
|
|
107
|
+
| `base64url` | `A-Z a-z 0-9 - _` |
|
|
108
|
+
| `alphabetic` | `A-Z a-z` |
|
|
109
|
+
| `numeric` | `0-9` |
|
|
110
|
+
| `hex` | `0-9 a-f` |
|
|
111
|
+
| `base16` | `0-9 A-F` |
|
|
112
|
+
|
|
113
|
+
## Expiring keys
|
|
114
|
+
|
|
115
|
+
Set `expiry` (minutes). The returned key **is a string** but also carries expiry metadata:
|
|
116
|
+
|
|
117
|
+
```python
|
|
118
|
+
key = generate_api_key(expiry=60)
|
|
119
|
+
|
|
120
|
+
headers = {"Authorization": key} # works — it's a str
|
|
121
|
+
key.expires_at # unix timestamp
|
|
122
|
+
key.is_expired # False (until 60 min pass)
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
## Derived keys (secret + seed)
|
|
126
|
+
|
|
127
|
+
Provide both `secret` and `seed` to derive the key deterministically from them
|
|
128
|
+
(HMAC-SHA256). A random salt still makes each generated key unique:
|
|
129
|
+
|
|
130
|
+
```python
|
|
131
|
+
generate_api_key("mysecret", "user-42", length=20, include="prod")
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
## Async is optional
|
|
135
|
+
|
|
136
|
+
The library is synchronous by default. When you need an awaitable:
|
|
137
|
+
|
|
138
|
+
```python
|
|
139
|
+
from generateApiKey import generate_api_key_async
|
|
140
|
+
|
|
141
|
+
api_key = await generate_api_key_async(length=48, prefix="sk")
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
> The original `await generateApiKey(secret, seed, ...)` still works unchanged
|
|
145
|
+
> for backwards compatibility, but `generate_api_key` is recommended.
|
|
146
|
+
|
|
147
|
+
## Error handling
|
|
148
|
+
|
|
149
|
+
```python
|
|
150
|
+
try:
|
|
151
|
+
api_key = generate_api_key(length=32)
|
|
152
|
+
except ValueError as e:
|
|
153
|
+
print(e) # e.g. bad length, or only one of secret/seed given
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
# Parameters
|
|
157
|
+
|
|
158
|
+
All parameters are optional. Call `generate_api_key()` with nothing for a secure default.
|
|
159
|
+
|
|
160
|
+
| **Parameter** | **Type** | **Default** | **Description** |
|
|
161
|
+
|---------------|----------|-------------|-----------------|
|
|
162
|
+
| `secret` | `str` | `None` | Optional secret. Given with `seed`, the key is HMAC-derived instead of random. |
|
|
163
|
+
| `seed` | `str` | `None` | Optional per-key value, used together with `secret`. |
|
|
164
|
+
| `length` | `int` | `32` | Number of characters in the key body. |
|
|
165
|
+
| `charset` | `str` | `"alphanumeric"` | Preset name (see table) or a literal string of allowed characters. |
|
|
166
|
+
| `case` | `str` | `"mixed"` | `"mixed"`, `"lower"` or `"upper"`. Affects letters only. |
|
|
167
|
+
| `prefix` | `str` | `None` | Prefix joined with `separator`, e.g. `sk-...`. |
|
|
168
|
+
| `separator` | `str` | `"-"` | String between prefix and key. |
|
|
169
|
+
| `dashes` | `bool` | `False` | Group the key with dashes for readability. |
|
|
170
|
+
| `dash_group` | `int` | `4` | Group size when `dashes=True`. |
|
|
171
|
+
| `include` | `str` | `None` | Extra value mixed into a derived key (needs `secret` + `seed`). |
|
|
172
|
+
| `expiry` | `int` | `None` | Expiry in minutes; sets `.expires_at` / `.is_expired`. |
|
|
173
|
+
|
|
174
|
+
Returns an `ApiKey` — a `str` subclass, so it works anywhere a string does.
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
By using this package, you are solely liable for any legal issues that may arise from its unauthorized use or misuse, as well as any security risks that may result from not properly securing the secret key used to generate the API keys.
|
|
178
|
+
|
|
179
|
+
# Fair Use Policy:
|
|
180
|
+
|
|
181
|
+
This package is provided as is, without any warranties or guarantees of any kind. We are not liable for any damages or losses that may result from its use. We reserve the right to change or discontinue the package at any time without notice.
|
|
182
|
+
|
|
183
|
+
We encourage you to use the package responsibly, and to report any security issues or bugs you may encounter.
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
Made with ❤️ , **Happy coding! 🚀**
|
|
@@ -3,8 +3,10 @@ MANIFEST.in
|
|
|
3
3
|
README.md
|
|
4
4
|
setup.py
|
|
5
5
|
generateApiKey/__init__.py
|
|
6
|
+
generateApiKey/utils.py
|
|
6
7
|
generateApiKey.egg-info/PKG-INFO
|
|
7
8
|
generateApiKey.egg-info/SOURCES.txt
|
|
8
9
|
generateApiKey.egg-info/dependency_links.txt
|
|
9
10
|
generateApiKey.egg-info/requires.txt
|
|
10
|
-
generateApiKey.egg-info/top_level.txt
|
|
11
|
+
generateApiKey.egg-info/top_level.txt
|
|
12
|
+
tests/test_generate.py
|
|
@@ -7,7 +7,7 @@ README = (file / "README.md").read_text()
|
|
|
7
7
|
|
|
8
8
|
setuptools.setup(
|
|
9
9
|
name="generateApiKey",
|
|
10
|
-
version="0.4.
|
|
10
|
+
version="0.4.8",
|
|
11
11
|
author="Nuhman Pk",
|
|
12
12
|
author_email="nuhmanpk7@gmail.com",
|
|
13
13
|
long_description = README,
|
|
@@ -25,5 +25,11 @@ setuptools.setup(
|
|
|
25
25
|
],
|
|
26
26
|
packages=setuptools.find_packages(include=['generateApiKey']),
|
|
27
27
|
python_requires=">=3.9",
|
|
28
|
+
project_urls={
|
|
29
|
+
'Documentation': 'https://github.com/nuhmanpk/generate-api-key/blob/main/README.md',
|
|
30
|
+
'Funding': 'https://github.com/sponsors/nuhmanpk',
|
|
31
|
+
'Source': 'https://github.com/nuhmanpk/generate-api-key/',
|
|
32
|
+
'Tracker': 'https://github.com/nuhmanpk/generate-api-key/issues',
|
|
33
|
+
},
|
|
28
34
|
|
|
29
35
|
)
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import time
|
|
2
|
+
import asyncio
|
|
3
|
+
|
|
4
|
+
from generateApiKey import (
|
|
5
|
+
generate_api_key,
|
|
6
|
+
generate_api_key_async,
|
|
7
|
+
generateApiKey,
|
|
8
|
+
ApiKey,
|
|
9
|
+
is_expired,
|
|
10
|
+
CHARSETS,
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def test_default_length_and_charset():
|
|
15
|
+
key = generate_api_key()
|
|
16
|
+
assert isinstance(key, ApiKey) and isinstance(key, str)
|
|
17
|
+
assert len(key) == 32
|
|
18
|
+
assert all(c in CHARSETS["alphanumeric"] for c in key)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def test_length():
|
|
22
|
+
assert len(generate_api_key(length=48)) == 48
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def test_charset_hex():
|
|
26
|
+
key = generate_api_key(charset="hex", length=40)
|
|
27
|
+
assert all(c in CHARSETS["hex"] for c in key)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def test_case_upper():
|
|
31
|
+
key = generate_api_key(charset="alphabetic", case="upper", length=20)
|
|
32
|
+
assert key.isupper()
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def test_custom_charset():
|
|
36
|
+
key = generate_api_key(charset="AB12", length=16)
|
|
37
|
+
assert set(key) <= set("AB12")
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def test_prefix():
|
|
41
|
+
assert generate_api_key(prefix="sk", length=8).startswith("sk-")
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def test_dashes():
|
|
45
|
+
key = generate_api_key(dashes=True, dash_group=4, length=16)
|
|
46
|
+
assert key.count("-") == 3
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def test_expiry_metadata():
|
|
50
|
+
key = generate_api_key(expiry=60)
|
|
51
|
+
assert key.expires_at is not None
|
|
52
|
+
assert not key.is_expired
|
|
53
|
+
assert not is_expired(key)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def test_expired():
|
|
57
|
+
past = ApiKey("x", int(time.time()) - 1)
|
|
58
|
+
assert past.is_expired
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def test_uniqueness():
|
|
62
|
+
assert len({generate_api_key() for _ in range(1000)}) == 1000
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def test_secret_seed_pair_required():
|
|
66
|
+
for kwargs in ({"secret": "x"}, {"seed": "y"}):
|
|
67
|
+
try:
|
|
68
|
+
generate_api_key(**kwargs)
|
|
69
|
+
assert False, "expected ValueError"
|
|
70
|
+
except ValueError:
|
|
71
|
+
pass
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def test_bad_length():
|
|
75
|
+
try:
|
|
76
|
+
generate_api_key(length=0)
|
|
77
|
+
assert False
|
|
78
|
+
except ValueError:
|
|
79
|
+
pass
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def test_async_wrapper():
|
|
83
|
+
key = asyncio.run(generate_api_key_async(length=8))
|
|
84
|
+
assert len(key) == 8
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def test_legacy_async():
|
|
88
|
+
key = asyncio.run(generateApiKey("s", "seed", prefix="hf", add_dashes=True))
|
|
89
|
+
assert key.startswith("hf-")
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
if __name__ == "__main__":
|
|
93
|
+
for name, fn in sorted(globals().items()):
|
|
94
|
+
if name.startswith("test_"):
|
|
95
|
+
fn()
|
|
96
|
+
print("ok", name)
|
|
97
|
+
print("all passed")
|
generateApiKey-0.4.5/README.md
DELETED
|
@@ -1,124 +0,0 @@
|
|
|
1
|
-
[](https://pepy.tech/project/generateApiKey)
|
|
2
|
-
[](https://pypi.org/project/YoutubeTags)
|
|
3
|
-

|
|
4
|
-

|
|
5
|
-
[](https://generateApiKey.readthedocs.io/en/latest/?badge=latest)
|
|
6
|
-

|
|
7
|
-
[](https://pepy.tech/project/generateApiKey)
|
|
8
|
-
[](https://github.com/nuhmanpk/generate-api-key/actions/workflows/Pypi-uploads.yml)
|
|
9
|
-

|
|
10
|
-
# API Key Generation Package
|
|
11
|
-
|
|
12
|
-
Timestamp and Numeric Representation: Now, the package incorporates a time-based and date-based hashing mechanism, adding an extra layer of security to your API keys. It captures the current timestamp and numeric representation of the key generation process, creating a unique identifier that's closely tied to the moment it was generated. This feature adds an element of time-based uniqueness to your keys, making them even more secure and less predictable.
|
|
13
|
-
|
|
14
|
-
This package provides a convenient way to generate API keys using a secret, seed, and an optional include keyword. The generated keys are unique and secure, making them suitable for use in a variety of applications.
|
|
15
|
-
|
|
16
|
-
The package supports generating API keys using a variety of methods such as UUID v5 and SHA-256 algorithm. The keys are generated using a combination of seed, secret, and include keyword. Additionally, the package allows you to insert the include keyword at a random position in the seed which will make it more difficult to guess.
|
|
17
|
-
|
|
18
|
-
It is important to keep the secret used to generate the keys secure and not share it with unauthorized parties. Additionally, the package can only be used for legitimate and legal purposes.
|
|
19
|
-
|
|
20
|
-
Please keep in mind that, even though this package provides a secure way to generate API keys, it is still important to use other security measures such as rate limiting, IP whitelisting, and encryption to protect your API and the data it accesses.
|
|
21
|
-
|
|
22
|
-
By using this package, you agree to take all necessary precautions to protect the data and resources accessed with the keys from unauthorized access or misuse. It is recommended to consult with a security expert before using this package or handling sensitive data.
|
|
23
|
-
|
|
24
|
-
# Privacy Policy
|
|
25
|
-
|
|
26
|
-
This package generates API keys that can be used to access sensitive data or resources. By using this package, you agree to keep the secret used to generate the keys secure and not share it with unauthorized parties. Additionally, the package can only be used for legitimate and legal purposes.
|
|
27
|
-
|
|
28
|
-
Please be aware that the package may cause a security risk if not used properly. The authors of this package cannot be held responsible for any unauthorized access or misuse of the keys generated by this package.
|
|
29
|
-
|
|
30
|
-
It is the user's responsibility to ensure the security of the keys and the protection of the data. It is recommended to consult with a security expert before using this package or handling sensitive data.
|
|
31
|
-
|
|
32
|
-
By using this package, you agree to take all necessary precautions to protect the data and resources accessed with the keys from unauthorized access or misuse.
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
# Installation
|
|
37
|
-
To install your package, you can use the pip package manager by running the following command in your command line:
|
|
38
|
-
|
|
39
|
-
```python
|
|
40
|
-
pip install generateApiKey
|
|
41
|
-
```
|
|
42
|
-
|
|
43
|
-
# Importing the package
|
|
44
|
-
Once the package is installed, you can import the package in your code by using the import statement:
|
|
45
|
-
```python
|
|
46
|
-
from generateApiKey import generateApiKey
|
|
47
|
-
```
|
|
48
|
-
# Generating an API key
|
|
49
|
-
To generate an API key, you can use the generateApiKey() function and pass in the secret, seed, and an optional include keyword. For example:
|
|
50
|
-
|
|
51
|
-
```python
|
|
52
|
-
from generateApiKey import generateApiKey
|
|
53
|
-
|
|
54
|
-
seed='12'
|
|
55
|
-
secret='Topsecrect'
|
|
56
|
-
api_key=generateApiKey(secret,seed)
|
|
57
|
-
print(api_key)
|
|
58
|
-
```
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
```python
|
|
62
|
-
from generateApiKey import generateApiKey
|
|
63
|
-
api_key = generateApiKey(secret='Topsecret', seed='12',include='user1')
|
|
64
|
-
print(api_key)
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
```python
|
|
68
|
-
from generateApiKey import generateApiKey
|
|
69
|
-
api_key = generateApiKey(secret='Topsecret', seed='12',include='user1',add_dashes=True)
|
|
70
|
-
print(api_key)
|
|
71
|
-
```
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
```python
|
|
75
|
-
secret = 'mysecret'
|
|
76
|
-
seed = 'randomseed'
|
|
77
|
-
include = "TopSecretWord"
|
|
78
|
-
api_key = generateApiKey(secret, seed, include)
|
|
79
|
-
print(api_key)
|
|
80
|
-
```
|
|
81
|
-
This will generate an API key based on the provided secret, seed, and include keyword.
|
|
82
|
-
|
|
83
|
-
## Error handling
|
|
84
|
-
It is a good practice to handle errors, you can use the try and except block to handle any exception that may occur during the key generation process.
|
|
85
|
-
|
|
86
|
-
```python
|
|
87
|
-
try:
|
|
88
|
-
secret = 'mysecret'
|
|
89
|
-
seed = 'randomseed'
|
|
90
|
-
include = "Production"
|
|
91
|
-
api_key = generateApiKey(secret, seed, include)
|
|
92
|
-
print(api_key)
|
|
93
|
-
except Exception as e:
|
|
94
|
-
print(e)
|
|
95
|
-
```
|
|
96
|
-
|
|
97
|
-
You can use the None return in the package function, to check if the key generation was successful.
|
|
98
|
-
|
|
99
|
-
```python
|
|
100
|
-
api_key = generateApiKey(secret, seed, include)
|
|
101
|
-
if api_key is None:
|
|
102
|
-
print("Failed to generate api key")
|
|
103
|
-
else:
|
|
104
|
-
print(api_key)
|
|
105
|
-
```
|
|
106
|
-
# Parameters
|
|
107
|
-
|
|
108
|
-
| **Variable** | **Type** | **Required** | **Example Value** | Description |
|
|
109
|
-
|----------|---------|-----------|--------------------|-------------|
|
|
110
|
-
| secret | `String` | Yes | "Topsecret" | The secret key used to generate the API key. It should be kept private and not shared with unauthorized parties. |
|
|
111
|
-
| seed | `String` | Yes | "12" | A value used to seed the generation of the API key. It can be any value, but it should be unique for each key. |
|
|
112
|
-
| include | `String` | Optional | "user1" | An optional value that can be included in the generated API key. It can be used to identify the user or application associated with the key. |
|
|
113
|
-
| add_dashes | `boolean` | Optional | True | A value used to determine wheather to add dashes or not in a key |
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
By using this package, you are solely liable for any legal issues that may arise from its unauthorized use or misuse, as well as any security risks that may result from not properly securing the secret key used to generate the API keys.
|
|
117
|
-
|
|
118
|
-
# Fair Use Policy:
|
|
119
|
-
|
|
120
|
-
This package is provided as is, without any warranties or guarantees of any kind. We are not liable for any damages or losses that may result from its use. We reserve the right to change or discontinue the package at any time without notice.
|
|
121
|
-
|
|
122
|
-
We encourage you to use the package responsibly, and to report any security issues or bugs you may encounter.
|
|
123
|
-
|
|
124
|
-
[Nuhman Pk](https://github.com/nuhmanpk)
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
import hashlib
|
|
2
|
-
import hmac
|
|
3
|
-
import uuid
|
|
4
|
-
import random
|
|
5
|
-
import os
|
|
6
|
-
import base64
|
|
7
|
-
import re
|
|
8
|
-
import time
|
|
9
|
-
import datetime
|
|
10
|
-
from cryptography.hazmat.primitives import hashes
|
|
11
|
-
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
def generateApiKey(secret, seed, include=None, add_dashes=False):
|
|
15
|
-
try:
|
|
16
|
-
current_timestamp = int(time.time())
|
|
17
|
-
now = datetime.datetime.now()
|
|
18
|
-
pbkdf2_iterations = random.randint(1000,10000)
|
|
19
|
-
numeric_representation = int(
|
|
20
|
-
f"{now.year}{now.month:02d}{now.day:02d}{now.hour:02d}{now.minute:02d}{now.second:02d}"
|
|
21
|
-
)
|
|
22
|
-
timestamp_hash = hashlib.sha256(
|
|
23
|
-
str(current_timestamp).encode()).hexdigest()
|
|
24
|
-
numeric_hash = hashlib.sha256(
|
|
25
|
-
str(numeric_representation).encode()).hexdigest()
|
|
26
|
-
|
|
27
|
-
if add_dashes:
|
|
28
|
-
message = str(seed).encode()
|
|
29
|
-
if include:
|
|
30
|
-
pos = random.randint(0, 32)
|
|
31
|
-
message = message[:pos] + include.encode() + message[pos:]
|
|
32
|
-
|
|
33
|
-
combined_hash = f"{timestamp_hash}{numeric_hash}{message}"
|
|
34
|
-
|
|
35
|
-
combined_hash = ''.join(random.sample(
|
|
36
|
-
combined_hash, len(combined_hash)))
|
|
37
|
-
api_key = hmac.new(
|
|
38
|
-
secret.encode(), combined_hash.encode(), hashlib.sha256).hexdigest()
|
|
39
|
-
return str(uuid.uuid5(uuid.NAMESPACE_DNS, api_key))
|
|
40
|
-
else:
|
|
41
|
-
salt = os.urandom(16)
|
|
42
|
-
kdf = PBKDF2HMAC(
|
|
43
|
-
algorithm=hashes.SHA256(),
|
|
44
|
-
salt=salt,
|
|
45
|
-
iterations=pbkdf2_iterations,
|
|
46
|
-
length=32
|
|
47
|
-
)
|
|
48
|
-
seed = f'{seed}{current_timestamp}{numeric_hash}'.encode()
|
|
49
|
-
if include:
|
|
50
|
-
pos = random.randint(0, len(seed))
|
|
51
|
-
seed = seed[:pos] + include.encode() + seed[pos:]
|
|
52
|
-
key_bytes = kdf.derive(seed)
|
|
53
|
-
key_base64 = base64.urlsafe_b64encode(key_bytes).decode()
|
|
54
|
-
api_key = re.sub(r'[^a-zA-Z0-9]', '', key_base64)
|
|
55
|
-
return api_key
|
|
56
|
-
except Exception as e:
|
|
57
|
-
print(e)
|
|
58
|
-
return None
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|