f-layer 2.0.0__py3-none-any.whl
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.
- f_layer-2.0.0.dist-info/METADATA +232 -0
- f_layer-2.0.0.dist-info/RECORD +45 -0
- f_layer-2.0.0.dist-info/WHEEL +4 -0
- f_layer-2.0.0.dist-info/entry_points.txt +2 -0
- f_layer-2.0.0.dist-info/licenses/LICENSE +201 -0
- flayer/__init__.py +5 -0
- flayer/__main__.py +247 -0
- flayer/_vpn_guest.py +130 -0
- flayer/core/__init__.py +1 -0
- flayer/core/config.py +198 -0
- flayer/core/contracts.py +114 -0
- flayer/core/lifecycle.py +767 -0
- flayer/core/state.py +351 -0
- flayer/diagnostics/__init__.py +20 -0
- flayer/diagnostics/benchmark.py +272 -0
- flayer/diagnostics/contracts.py +167 -0
- flayer/diagnostics/health.py +154 -0
- flayer/diagnostics/reporting.py +24 -0
- flayer/extensions/__init__.py +25 -0
- flayer/extensions/builtins.py +165 -0
- flayer/extensions/contracts.py +196 -0
- flayer/extensions/discovery.py +152 -0
- flayer/extensions/registry.py +347 -0
- flayer/guest.py +270 -0
- flayer/integrations/__init__.py +23 -0
- flayer/integrations/adapters.py +92 -0
- flayer/integrations/contracts.py +241 -0
- flayer/integrations/wire.py +273 -0
- flayer/profiles/__init__.py +33 -0
- flayer/profiles/_amnezia_export.py +176 -0
- flayer/profiles/_vless_guest.py +432 -0
- flayer/profiles/amneziawg.py +555 -0
- flayer/profiles/artifacts.py +609 -0
- flayer/profiles/gateway.py +729 -0
- flayer/profiles/static_site.py +596 -0
- flayer/profiles/vless.py +422 -0
- flayer/profiles/vpn.py +524 -0
- flayer/providers/__init__.py +1 -0
- flayer/providers/contracts.py +207 -0
- flayer/providers/lifecycle.py +177 -0
- flayer/providers/yandex.py +387 -0
- flayer/providers/yandex_lifecycle.py +781 -0
- flayer/py.typed +0 -0
- flayer/vpn_export.py +72 -0
- flayer/vpn_project.py +828 -0
flayer/py.typed
ADDED
|
File without changes
|
flayer/vpn_export.py
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"""Offline export of existing owned VPN device files with native AmneziaVPN profiles."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
from flayer.core.contracts import ValidateName
|
|
8
|
+
from flayer.guest import PrivatePath
|
|
9
|
+
from flayer.profiles._amnezia_export import BuildAmneziaQrArtifacts, BuildAmneziaWgArtifacts
|
|
10
|
+
from flayer.profiles.artifacts import (
|
|
11
|
+
Artifact,
|
|
12
|
+
ArtifactBundle,
|
|
13
|
+
ReadOwnedArtifactFile,
|
|
14
|
+
WriteArtifactBundle,
|
|
15
|
+
)
|
|
16
|
+
from flayer.profiles.vpn import VpnError
|
|
17
|
+
from flayer.vpn_project import VpnProject, VpnProjectReport
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def ExportVpnDevice(
|
|
21
|
+
project: VpnProject, device_id: str, protocol: str, output: str | Path, *, qr: bool = False,
|
|
22
|
+
) -> VpnProjectReport:
|
|
23
|
+
"""Copy one manifest-verified device without cloud calls, key generation, or source writes."""
|
|
24
|
+
|
|
25
|
+
ValidateName(device_id, "device_id")
|
|
26
|
+
|
|
27
|
+
if device_id not in {device.device_id for device in project.vpn.devices}:
|
|
28
|
+
raise VpnError("Export requires a device declared in project.toml")
|
|
29
|
+
|
|
30
|
+
if protocol not in {"amneziawg", "vless-reality"} or type(qr) is not bool:
|
|
31
|
+
raise VpnError("Export requires a supported protocol and boolean QR option")
|
|
32
|
+
|
|
33
|
+
output_root = Path(output).absolute()
|
|
34
|
+
|
|
35
|
+
if ".." in output_root.parts or output_root.is_relative_to(project.Artifacts.absolute()):
|
|
36
|
+
raise VpnError("Export output must be separate from the source artifact store and contain no traversal")
|
|
37
|
+
|
|
38
|
+
if output_root.exists() or output_root.is_symlink():
|
|
39
|
+
PrivatePath(output_root, directory=True)
|
|
40
|
+
|
|
41
|
+
name = f"{device_id}-{protocol}"
|
|
42
|
+
ValidateName(name, "artifact name")
|
|
43
|
+
source = project.Artifacts / f"device-{name}"
|
|
44
|
+
filenames = ("amneziawg.conf",) if protocol == "amneziawg" else ("client.json", "import.txt", "amnezia.vpn")
|
|
45
|
+
artifacts = tuple(Artifact(filename, ReadOwnedArtifactFile(
|
|
46
|
+
source / filename, project.vpn.identity, kind="device", name=name,
|
|
47
|
+
)) for filename in filenames)
|
|
48
|
+
|
|
49
|
+
if protocol == "amneziawg":
|
|
50
|
+
artifacts += BuildAmneziaWgArtifacts(artifacts[0].content, device_id, qr=qr)
|
|
51
|
+
|
|
52
|
+
elif qr:
|
|
53
|
+
artifacts += BuildAmneziaQrArtifacts(artifacts[-1].content)
|
|
54
|
+
|
|
55
|
+
bundle = ArtifactBundle(project.vpn.identity, "device", name, artifacts)
|
|
56
|
+
destination = output_root / f"device-{name}"
|
|
57
|
+
|
|
58
|
+
if destination.exists() or destination.is_symlink():
|
|
59
|
+
for artifact in artifacts:
|
|
60
|
+
actual = ReadOwnedArtifactFile(destination / artifact.name, bundle.identity, kind="device", name=name)
|
|
61
|
+
|
|
62
|
+
if actual != artifact.content:
|
|
63
|
+
raise VpnError("Existing export differs; choose a separate output directory")
|
|
64
|
+
|
|
65
|
+
if {item.name for item in destination.iterdir()} != {"manifest.json", *(item.name for item in artifacts)}:
|
|
66
|
+
raise VpnError("Existing export has a different file selection; choose a separate output directory")
|
|
67
|
+
|
|
68
|
+
else:
|
|
69
|
+
WriteArtifactBundle(output_root, bundle)
|
|
70
|
+
|
|
71
|
+
return VpnProjectReport("export", "complete", client_exports=(str(destination),),
|
|
72
|
+
details="Existing device files exported privately; no connectivity check was performed")
|