0
# Utility Functions
1
2
General utility functions for file operations, system information, validation, and process management used throughout Certbot operations.
3
4
## Capabilities
5
6
### File and Directory Operations
7
8
Utilities for safely creating, managing, and accessing files and directories with proper permissions.
9
10
```python { .api }
11
def make_or_verify_dir(directory: str, mode: int, strict: bool = True) -> None:
12
"""
13
Create directory with specified permissions or verify existing directory.
14
15
Args:
16
directory: Directory path to create or verify
17
mode: File mode permissions (e.g., 0o700, 0o755)
18
strict: If true, raise exception if directory permissions don't match
19
20
Raises:
21
errors.Error: If directory creation fails or permissions are incorrect
22
"""
23
24
def safe_open(path: str, mode: str = 'w', chmod: int = 0o644) -> IO:
25
"""
26
Safely open a file with specified permissions.
27
28
Args:
29
path: File path to open
30
mode: File open mode (e.g., 'w', 'r', 'a')
31
chmod: File permissions to set
32
33
Returns:
34
File object handle
35
36
Raises:
37
OSError: If file cannot be opened
38
"""
39
40
def unique_file(path: str, chmod: int = 0o644, mode: str = 'w') -> tuple[IO, str]:
41
"""
42
Create a unique filename if the specified path already exists.
43
44
Args:
45
path: Desired file path
46
chmod: File permissions to set
47
mode: File open mode
48
49
Returns:
50
Tuple of (file_handle, actual_path_used)
51
"""
52
53
def unique_lineage_name(path: str, filename: str) -> tuple[IO, str]:
54
"""
55
Create a unique lineage filename for certificate storage.
56
57
Args:
58
path: Directory path for lineage
59
filename: Base filename for lineage
60
61
Returns:
62
Tuple of (file_handle, unique_filename)
63
"""
64
65
def safely_remove(path: str) -> None:
66
"""
67
Remove a file that may or may not exist without raising errors.
68
69
Args:
70
path: Path to file to remove
71
"""
72
73
def lock_dir_until_exit(dir_path: str) -> None:
74
"""
75
Lock a directory until the program exits.
76
77
Args:
78
dir_path: Directory to lock
79
80
Raises:
81
errors.LockError: If directory cannot be locked
82
"""
83
84
def set_up_core_dir(directory: str, mode: int, strict: bool = True) -> None:
85
"""
86
Create and lock a core Certbot directory.
87
88
Args:
89
directory: Directory path to set up
90
mode: Directory permissions
91
strict: Whether to enforce strict permissions
92
"""
93
```
94
95
### System Information
96
97
Functions to gather operating system and platform information.
98
99
```python { .api }
100
def get_os_info() -> tuple[str, str]:
101
"""
102
Get operating system name and version.
103
104
Returns:
105
Tuple of (os_name, os_version)
106
"""
107
108
def get_os_info_ua() -> str:
109
"""
110
Get OS information formatted for User Agent strings.
111
112
Returns:
113
OS information string suitable for HTTP User-Agent header
114
"""
115
116
def get_systemd_os_like() -> list[str]:
117
"""
118
Get systemd OS likeness information from /etc/os-release.
119
120
Returns:
121
List of OS distributions this system is like
122
"""
123
124
def get_var_from_file(varname: str, filepath: str) -> str:
125
"""
126
Extract variable value from systemd-style configuration file.
127
128
Args:
129
varname: Variable name to extract
130
filepath: Path to configuration file
131
132
Returns:
133
Variable value as string
134
"""
135
136
def get_python_os_info(pretty: bool = False) -> tuple[str, str]:
137
"""
138
Get OS information using Python's platform module.
139
140
Args:
141
pretty: Whether to return pretty-formatted names
142
143
Returns:
144
Tuple of (os_name, os_version)
145
"""
146
```
147
148
### Process and Command Execution
149
150
Utilities for running external commands and managing subprocess execution.
151
152
```python { .api }
153
def run_script(params: list[str]) -> tuple[str, str]:
154
"""
155
Run external command/script with parameters.
156
157
Args:
158
params: List of command and arguments
159
160
Returns:
161
Tuple of (stdout, stderr) output
162
163
Raises:
164
errors.SubprocessError: If command execution fails
165
"""
166
167
def exe_exists(exe: str) -> bool:
168
"""
169
Check if executable exists in the system PATH.
170
171
Args:
172
exe: Executable name to check
173
174
Returns:
175
True if executable is found in PATH
176
"""
177
```
178
179
### Validation Functions
180
181
Domain name and email validation utilities for ensuring input correctness.
182
183
```python { .api }
184
def safe_email(email: str) -> bool:
185
"""
186
Validate email address format using regex.
187
188
Args:
189
email: Email address to validate
190
191
Returns:
192
True if email format is valid
193
"""
194
195
def enforce_le_validity(domain: str) -> str:
196
"""
197
Validate domain name for Let's Encrypt compatibility.
198
199
Args:
200
domain: Domain name to validate
201
202
Returns:
203
Validated domain name
204
205
Raises:
206
errors.ConfigurationError: If domain is invalid for Let's Encrypt
207
"""
208
209
def enforce_domain_sanity(domain: Union[str, bytes]) -> str:
210
"""
211
Perform basic domain name validation.
212
213
Args:
214
domain: Domain name to validate
215
216
Returns:
217
Validated domain name as string
218
219
Raises:
220
errors.ConfigurationError: If domain format is invalid
221
"""
222
223
def is_ipaddress(address: str) -> bool:
224
"""
225
Check if string represents an IP address.
226
227
Args:
228
address: String to check
229
230
Returns:
231
True if address is a valid IP address
232
"""
233
234
def is_wildcard_domain(domain: Union[str, bytes]) -> bool:
235
"""
236
Check if domain is a wildcard domain (starts with *.).
237
238
Args:
239
domain: Domain to check
240
241
Returns:
242
True if domain is wildcard format
243
"""
244
245
def is_staging(srv: str) -> bool:
246
"""
247
Determine if ACME server URL is a staging server.
248
249
Args:
250
srv: ACME server URL
251
252
Returns:
253
True if server appears to be staging/testing server
254
"""
255
256
def get_filtered_names(all_names: set[str]) -> set[str]:
257
"""
258
Filter domain names to those valid for Let's Encrypt.
259
260
Args:
261
all_names: Set of domain names to filter
262
263
Returns:
264
Set of names valid for Let's Encrypt certificates
265
"""
266
```
267
268
### Version and Environment Utilities
269
270
Version parsing and environment management functions.
271
272
```python { .api }
273
def parse_loose_version(version_string: str) -> list:
274
"""
275
Parse version string into comparable components.
276
277
Args:
278
version_string: Version string to parse
279
280
Returns:
281
List of version components (integers and strings)
282
"""
283
284
def env_no_snap_for_external_calls() -> dict[str, str]:
285
"""
286
Get environment variables for external command calls.
287
288
Returns:
289
Dictionary of environment variables with snap paths removed
290
"""
291
292
def atexit_register(func: Callable, *args: Any, **kwargs: Any) -> None:
293
"""
294
Register function to be called at program exit.
295
296
Args:
297
func: Function to call at exit
298
args: Positional arguments for function
299
kwargs: Keyword arguments for function
300
"""
301
```
302
303
## Usage Examples
304
305
### File Operations
306
307
```python
308
from certbot import util
309
310
# Create directory with proper permissions
311
util.make_or_verify_dir('/etc/letsencrypt/live', 0o700, strict=True)
312
313
# Safely create unique files
314
with util.safe_open('/etc/letsencrypt/accounts/account.json', 'w', 0o600) as f:
315
f.write(account_data)
316
317
# Get unique filename if original exists
318
file_handle, actual_path = util.unique_file('/etc/letsencrypt/csr/example.csr')
319
```
320
321
### System Information
322
323
```python
324
from certbot import util
325
326
# Get OS information
327
os_name, os_version = util.get_os_info()
328
print(f"Running on {os_name} {os_version}")
329
330
# Check for executable availability
331
if util.exe_exists('apache2ctl'):
332
print("Apache is available")
333
```
334
335
### Validation
336
337
```python
338
from certbot import util
339
340
# Validate email
341
if util.safe_email('user@example.com'):
342
print("Valid email address")
343
344
# Validate domains
345
try:
346
domain = util.enforce_le_validity('example.com')
347
print(f"Valid domain: {domain}")
348
except errors.ConfigurationError:
349
print("Invalid domain for Let's Encrypt")
350
351
# Check for wildcard domains
352
if util.is_wildcard_domain('*.example.com'):
353
print("Wildcard domain detected")
354
```
355
356
## Types
357
358
```python { .api }
359
class LooseVersion:
360
"""
361
Version comparison utility with loose rules.
362
363
Supports version strings with mixed integer and string components.
364
"""
365
366
def __init__(self, version_string: str):
367
"""Parse version string into components."""
368
369
def try_risky_comparison(self, other: 'LooseVersion') -> int:
370
"""
371
Compare with another LooseVersion.
372
373
Returns:
374
0 if equal, 1 if self > other, -1 if self < other
375
376
Raises:
377
errors.Error: If versions are incompatible for comparison
378
"""
379
380
# Environment and system constants
381
EMAIL_REGEX: str # Regular expression for email validation
382
ANSI_SGR_BOLD: str # ANSI bold formatting code
383
ANSI_SGR_RED: str # ANSI red color code
384
ANSI_SGR_RESET: str # ANSI reset formatting code
385
```