Skip to content

Commit 474c72d

Browse files
committed
Refactor mkcert
1 parent 77e2f80 commit 474c72d

File tree

2 files changed

+107
-95
lines changed

2 files changed

+107
-95
lines changed

plain-dev/plain/dev/cli.py

Lines changed: 11 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
11
import json
22
import os
33
import platform
4-
import shutil
54
import subprocess
65
import sys
7-
import urllib.request
86
from importlib.util import find_spec
97
from pathlib import Path
108

@@ -15,6 +13,7 @@
1513
from plain.runtime import APP_PATH, settings
1614

1715
from .db import cli as db_cli
16+
from .mkcert import MkcertManager
1817
from .pid import Pid
1918
from .services import Services
2019
from .utils import has_pyproject_toml, plainpackage_installed
@@ -62,25 +61,20 @@ def __init__(self, *, port):
6261
}
6362
self.project_name = os.path.basename(os.getcwd())
6463
self.domain = f"{self.project_name}.localhost"
65-
66-
# Paths for mkcert and certificates
67-
self.mkcert_dir = Path.home() / ".plain" / "dev"
68-
self.mkcert_bin = self.mkcert_dir / "mkcert"
69-
self.certs_dir = (
70-
Path(settings.PLAIN_TEMP_PATH) / "dev" / "certs"
71-
) # Local project directory for certs
72-
73-
# Define certificate and key paths with clear filenames
74-
self.cert_path = self.certs_dir / f"{self.domain}-cert.pem"
75-
self.key_path = self.certs_dir / f"{self.domain}-key.pem"
64+
self.ssl_cert_path = None
65+
self.ssl_key_path = None
7666

7767
def run(self):
7868
pid = Pid()
7969
pid.write()
8070

8171
try:
82-
self.setup_mkcert()
83-
self.generate_certs()
72+
mkcert_manager = MkcertManager()
73+
mkcert_manager.setup_mkcert(install_path=Path.home() / ".plain" / "dev")
74+
self.ssl_cert_path, self.ssl_key_path = mkcert_manager.generate_certs(
75+
domain=self.domain,
76+
storage_path=Path(settings.PLAIN_TEMP_PATH) / "dev" / "certs",
77+
)
8478
self.modify_hosts_file()
8579
self.add_csrf_trusted_origins()
8680
self.add_allowed_hosts()
@@ -103,84 +97,6 @@ def run(self):
10397
finally:
10498
pid.rm()
10599

106-
def setup_mkcert(self):
107-
"""Set up mkcert by checking if it's installed or downloading the binary and installing the local CA."""
108-
if mkcert_path := shutil.which("mkcert"):
109-
# mkcert is already installed somewhere
110-
self.mkcert_bin = mkcert_path
111-
else:
112-
self.mkcert_dir.mkdir(parents=True, exist_ok=True)
113-
if not self.mkcert_bin.exists():
114-
system = platform.system()
115-
arch = platform.machine()
116-
117-
# Map platform.machine() to mkcert's expected architecture strings
118-
arch_map = {
119-
"x86_64": "amd64",
120-
"amd64": "amd64",
121-
"AMD64": "amd64",
122-
"arm64": "arm64",
123-
"aarch64": "arm64",
124-
}
125-
arch = arch_map.get(
126-
arch.lower(), "amd64"
127-
) # Default to amd64 if unknown
128-
129-
if system == "Darwin":
130-
os_name = "darwin"
131-
elif system == "Linux":
132-
os_name = "linux"
133-
elif system == "Windows":
134-
os_name = "windows"
135-
else:
136-
click.secho("Unsupported OS", fg="red")
137-
sys.exit(1)
138-
139-
mkcert_url = f"https://dl.filippo.io/mkcert/latest?for={os_name}/{arch}"
140-
click.secho(f"Downloading mkcert from {mkcert_url}...", bold=True)
141-
urllib.request.urlretrieve(mkcert_url, self.mkcert_bin)
142-
self.mkcert_bin.chmod(0o755)
143-
self.mkcert_bin = str(self.mkcert_bin) # Convert Path object to string
144-
145-
if not self.is_mkcert_ca_installed():
146-
click.secho(
147-
"Installing mkcert local CA. You may be prompted for your password.",
148-
bold=True,
149-
)
150-
subprocess.run([self.mkcert_bin, "-install"], check=True)
151-
152-
def is_mkcert_ca_installed(self):
153-
"""Check if mkcert local CA is already installed using mkcert -check."""
154-
try:
155-
result = subprocess.run([self.mkcert_bin, "-check"], capture_output=True)
156-
output = result.stdout.decode() + result.stderr.decode()
157-
if "The local CA is not installed" in output:
158-
return False
159-
return True
160-
except Exception as e:
161-
click.secho(f"Error checking mkcert CA installation: {e}", fg="red")
162-
return False
163-
164-
def generate_certs(self):
165-
if self.cert_path.exists() and self.key_path.exists():
166-
return
167-
168-
self.certs_dir.mkdir(parents=True, exist_ok=True)
169-
170-
# Generate SSL certificates using mkcert
171-
click.secho(f"Generating SSL certificates for {self.domain}...", bold=True)
172-
subprocess.run(
173-
[
174-
self.mkcert_bin,
175-
"-cert-file",
176-
str(self.cert_path),
177-
"-key-file",
178-
str(self.key_path),
179-
self.domain,
180-
],
181-
check=True,
182-
)
183-
184100
def modify_hosts_file(self):
185101
"""Modify the hosts file to map the custom domain to 127.0.0.1."""
186102
entry_identifier = "# Added by plain"
@@ -284,9 +200,9 @@ def add_gunicorn(self):
284200
"--bind",
285201
f"{self.domain}:{self.port}",
286202
"--certfile",
287-
str(self.cert_path),
203+
str(self.ssl_cert_path),
288204
"--keyfile",
289-
str(self.key_path),
205+
str(self.ssl_key_path),
290206
"--reload",
291207
"plain.wsgi:app",
292208
"--timeout",

plain-dev/plain/dev/mkcert.py

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
import platform
2+
import shutil
3+
import subprocess
4+
import sys
5+
import urllib.request
6+
7+
import click
8+
9+
10+
class MkcertManager:
11+
def __init__(self):
12+
self.mkcert_bin = None
13+
14+
def setup_mkcert(self, install_path):
15+
"""Set up mkcert by checking if it's installed or downloading the binary and installing the local CA."""
16+
if mkcert_path := shutil.which("mkcert"):
17+
# mkcert is already installed somewhere
18+
self.mkcert_bin = mkcert_path
19+
else:
20+
self.mkcert_bin = install_path / "mkcert"
21+
install_path.mkdir(parents=True, exist_ok=True)
22+
if not self.mkcert_bin.exists():
23+
system = platform.system()
24+
arch = platform.machine()
25+
26+
# Map platform.machine() to mkcert's expected architecture strings
27+
arch_map = {
28+
"x86_64": "amd64",
29+
"amd64": "amd64",
30+
"AMD64": "amd64",
31+
"arm64": "arm64",
32+
"aarch64": "arm64",
33+
}
34+
arch = arch_map.get(
35+
arch.lower(), "amd64"
36+
) # Default to amd64 if unknown
37+
38+
if system == "Darwin":
39+
os_name = "darwin"
40+
elif system == "Linux":
41+
os_name = "linux"
42+
elif system == "Windows":
43+
os_name = "windows"
44+
else:
45+
click.secho("Unsupported OS", fg="red")
46+
sys.exit(1)
47+
48+
mkcert_url = f"https://dl.filippo.io/mkcert/latest?for={os_name}/{arch}"
49+
click.secho(f"Downloading mkcert from {mkcert_url}...", bold=True)
50+
urllib.request.urlretrieve(mkcert_url, self.mkcert_bin)
51+
self.mkcert_bin.chmod(0o755)
52+
self.mkcert_bin = str(self.mkcert_bin) # Convert Path object to string
53+
54+
if not self.is_mkcert_ca_installed():
55+
click.secho(
56+
"Installing mkcert local CA. You may be prompted for your password.",
57+
bold=True,
58+
)
59+
subprocess.run([self.mkcert_bin, "-install"], check=True)
60+
61+
def is_mkcert_ca_installed(self):
62+
"""Check if mkcert local CA is already installed using mkcert -check."""
63+
try:
64+
result = subprocess.run([self.mkcert_bin, "-check"], capture_output=True)
65+
output = result.stdout.decode() + result.stderr.decode()
66+
if "The local CA is not installed" in output:
67+
return False
68+
return True
69+
except Exception as e:
70+
click.secho(f"Error checking mkcert CA installation: {e}", fg="red")
71+
return False
72+
73+
def generate_certs(self, domain, storage_path):
74+
cert_path = storage_path / f"{domain}-cert.pem"
75+
key_path = storage_path / f"{domain}-key.pem"
76+
77+
if cert_path.exists() and key_path.exists():
78+
return cert_path, key_path
79+
80+
storage_path.mkdir(parents=True, exist_ok=True)
81+
82+
# Generate SSL certificates using mkcert
83+
click.secho(f"Generating SSL certificates for {domain}...", bold=True)
84+
subprocess.run(
85+
[
86+
self.mkcert_bin,
87+
"-cert-file",
88+
str(cert_path),
89+
"-key-file",
90+
str(key_path),
91+
domain,
92+
],
93+
check=True,
94+
)
95+
96+
return cert_path, key_path

0 commit comments

Comments
 (0)