Files
bitwarden-desktop-agent/desktop_proxy.py

94 lines
2.2 KiB
Python
Raw Normal View History

2026-03-19 12:42:29 +09:00
#!/opt/homebrew/bin/python3
2026-03-18 17:47:10 +09:00
import socket
import struct
import sys
import threading
from pathlib import Path
2026-03-19 12:42:29 +09:00
MAX_MSG = 1024 * 1024
2026-03-18 17:47:10 +09:00
def ipc_socket_path() -> str:
2026-03-19 12:42:29 +09:00
return str(Path.home() / ".cache" / "com.bitwarden.desktop" / "s.bw")
def recv_exact(sock: socket.socket, n: int) -> bytes | None:
buf = b""
while len(buf) < n:
chunk = sock.recv(n - len(buf))
if not chunk:
return None
buf += chunk
return buf
2026-03-18 17:47:10 +09:00
2026-03-19 12:42:29 +09:00
def read_stdin() -> bytes | None:
2026-03-18 17:47:10 +09:00
header = sys.stdin.buffer.read(4)
if len(header) < 4:
return None
length = struct.unpack("=I", header)[0]
2026-03-19 12:42:29 +09:00
if length == 0 or length > MAX_MSG:
2026-03-18 17:47:10 +09:00
return None
data = sys.stdin.buffer.read(length)
2026-03-19 12:42:29 +09:00
return data if len(data) == length else None
2026-03-18 17:47:10 +09:00
2026-03-19 12:42:29 +09:00
def write_stdout(data: bytes):
sys.stdout.buffer.write(struct.pack("=I", len(data)) + data)
2026-03-18 17:47:10 +09:00
sys.stdout.buffer.flush()
2026-03-19 12:42:29 +09:00
def read_ipc(sock: socket.socket) -> bytes | None:
2026-03-18 17:47:10 +09:00
header = recv_exact(sock, 4)
if header is None:
return None
length = struct.unpack("=I", header)[0]
2026-03-19 12:42:29 +09:00
if length == 0 or length > MAX_MSG:
2026-03-18 17:47:10 +09:00
return None
return recv_exact(sock, length)
2026-03-19 12:42:29 +09:00
def send_ipc(sock: socket.socket, data: bytes):
2026-03-18 17:47:10 +09:00
sock.sendall(struct.pack("=I", len(data)) + data)
def ipc_to_stdout(sock: socket.socket):
try:
while True:
2026-03-19 12:42:29 +09:00
msg = read_ipc(sock)
2026-03-18 17:47:10 +09:00
if msg is None:
break
2026-03-19 12:42:29 +09:00
write_stdout(msg)
2026-03-18 17:47:10 +09:00
except (ConnectionResetError, BrokenPipeError, OSError):
pass
def main():
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
try:
2026-03-19 12:42:29 +09:00
sock.connect(ipc_socket_path())
2026-03-18 17:47:10 +09:00
except (FileNotFoundError, ConnectionRefusedError):
sys.exit(1)
2026-03-19 12:42:29 +09:00
send_ipc(sock, b'{"command":"connected"}')
threading.Thread(target=ipc_to_stdout, args=(sock,), daemon=True).start()
2026-03-18 17:47:10 +09:00
try:
while True:
2026-03-19 12:42:29 +09:00
msg = read_stdin()
2026-03-18 17:47:10 +09:00
if msg is None:
break
2026-03-19 12:42:29 +09:00
send_ipc(sock, msg)
2026-03-18 17:47:10 +09:00
except (BrokenPipeError, OSError):
pass
finally:
try:
2026-03-19 12:42:29 +09:00
send_ipc(sock, b'{"command":"disconnected"}')
2026-03-18 17:47:10 +09:00
except OSError:
pass
sock.close()
if __name__ == "__main__":
main()