Skip to main content

Cloud Socket is a secure websocket application that uses AES-GCM encryption and is build on fastapi. This also allows you to have google cloud run server without cold starts as it always has an open connection

Project description

☁️ cloud-socket

A lightweight, encrypted WebSocket communication library for Python and JavaScript that enables secure real-time client-server communication with automatic connection management and end-to-end encryption.

✨ Features

  • 🔒 End-to-end encryption using AES-GCM
  • 🔄 Automatic connection rotation to prevent timeouts
  • 🎯 Smart reconnection with window focus detection
  • 📦 Type-safe request/response with dataclass support
  • 🪝 Decorator-based method registration
  • 🔑 Flexible authentication - bring your own auth system
  • 📝 Built-in logging with customizable handlers
  • ❄️ No cold starts when hosted in cloud functions
  • 🎨 Framework agnostic - works with FastAPI or standalone

🚀 Installation

pip install cloud-socket

You'll also need the provided cloudSocket.js file in your frontend project.


📖 Learn by Example

Let's build a simple, secure echo service. This example will show you how to set up the backend, connect from the frontend, and call a Python function from JavaScript.

Step 1: Create the Python Backend

Create a file named main.py. This will be our server.

The server needs two key pieces of logic from you:

  1. A function to get a user-specific secret key for encryption.
  2. A function to validate a user's access token.
# main.py
import asyncio
from dataclasses import dataclass

from cloud_socket.auth import User
from cloud_socket.app import aserve
from cloud_socket.registry import register

# This is where you'd integrate your auth system (e.g., check a JWT)
# For this example, we'll just check if the token is not empty.
async def validate_access_token(user: User) -> bool:
    print(f"Validating token for user {user.uid}...")
    return bool(user.access_token)

# This function retrieves the secret key used for E2E encryption.
# IMPORTANT: This key should be securely managed and known only to the
# user and the server.
async def get_crypto_key(user: User) -> str:
    print(f"Fetching crypto key for user {user.uid}...")
    # In a real app, you might derive this from a user-specific secret.
    return f"super-secret-key-for-{user.uid}"

# Define the structure of the request body using a dataclass.
# The `body` argument in the client's `api` call must match this.
@dataclass
class EchoPayload:
    message: str

# Use the @register decorator to expose this function to clients.
# The function signature is flexible; `cloud-socket` injects the
# arguments it needs, like the validated `user` and the `body`.
@register("echo")
async def echo(user: User, body: EchoPayload):
    print(f"User {user.uid} sent message: {body.message}")
    return {"status": "ok", "response": f"Your message was: '{body.message}'"}

# Start the server
if __name__ == "__main__":
    print("Starting Cloud Socket server on ws://localhost:8003/ws")
    asyncio.run(
        aserve(
            get_crypto_key,
            validate_access_token,
            host="localhost",
            port=8003,
        )
    )

Step 2: Set Up the JavaScript Client

Place cloudSocket.js in your frontend source folder. Here's how you can use it in a simple React component.

// src/App.js
import { useEffect, useState } from 'react';
import { setup, api } from './cloudSocket'; // Adjust the import path

function App() {
  const [inputValue, setInputValue] = useState('Hello, world!');
  const [result, setResult] = useState(null);
  const [isLoading, setIsLoading] = useState(false);

  // Setup the connection when the component mounts
  useEffect(() => {
    const uid = 'user-123';
    
    // In a real app, the uid, access_token, and crypto_key
    // would come from your authentication flow after a user logs in.
    setup({
      url: 'ws://localhost:8003/ws',
      uid: uid,
      access_token: 'a-valid-user-token',
      crypto_key: `super-secret-key-for-${uid}`, // Must match the backend logic
    });
  }, []);

  const handleEcho = async () => {
    if (!inputValue) return;
    setIsLoading(true);
    setResult(null);
    try {
      // Call the backend function registered as "echo"
      const response = await api({
        method: 'echo',
        body: {
          message: inputValue, // This object must match the `EchoPayload` dataclass
        },
      });
      setResult(response);
    } catch (error) {
      console.error('API call failed:', error);
      setResult({ error: error.message });
    }
    setIsLoading(false);
  };

  return (
    <div>
      <h1>Cloud Socket Echo</h1>
      <input
        type="text"
        value={inputValue}
        onChange={(e) => setInputValue(e.target.value)}
        placeholder="Enter a message"
      />
      <button onClick={handleEcho} disabled={isLoading}>
        {isLoading ? 'Sending...' : 'Send Echo'}
      </button>
      {result && (
        <pre>
          <strong>Response from server:</strong>
          <br />
          {JSON.stringify(result, null, 2)}
        </pre>
      )}
    </div>
  );
}

export default App;

Step 3: Run It!

  1. Start the backend server:

    python main.py
    
  2. Start your frontend application:

    npm start 
    

Now, open your browser, type a message, and click the button. You'll see the response from the Python server appear on the screen! 🎉


⚙️ API Reference

Backend (Python)

serve() & aserve()

This is the main function to start the WebSocket server.

aserve(
    get_crypto_key: Callable[[User], str | Awaitable[str]],
    validate_access_token: Callable[[User], bool | Awaitable[bool]],
    host: str = 'localhost',
    port: int = 8003,
    log_handler: Callable[[CloudSocketLog], None] | None = None,
    get_user_info: Callable[[User], dict | Awaitable[dict]] | None = None,
)
  • get_crypto_key (required): An async or regular function that takes a User object and returns the user-specific secret string for deriving the encryption key.
  • validate_access_token (required): An async or regular function that takes a User object and returns True if their access_token is valid, False otherwise.
  • log_handler (optional): A function to process structured logs from the server.
  • get_user_info (optional): An async or regular function to fetch and cache additional user details, available via await user.get_info().

@register(method_name)

A decorator to expose a function as an RPC endpoint. The arguments for the decorated function are automatically injected based on their type annotations.

Supported injectable arguments:

  • user: User: The authenticated User object, containing uid, access_token, and user info.
  • body: <YourDataclass> or body: dict: The entire decrypted payload sent from the client.
  • <param_name>: <YourDataclass>: If your client sends { "body": { "param_name": { ... } } }, cloud-socket will automatically extract, validate, and deserialize param_name into your dataclass.

Frontend (JavaScript)

setup(config)

Initializes and configures the WebSocket manager. Call this once when your application loads.

setup({
    url: 'ws://your-server/ws',
    uid: 'user-id-from-auth',
    access_token: 'user-token-from-auth',
    crypto_key: 'user-secret-for-encryption',
});

api(request)

Sends a secure request to the backend and returns a Promise that resolves with the server's response.

const response = await api({
    method: 'method_name', // The string name from @register()
    body: { /* your JSON-serializable payload */ }
});

🔒 A Note on Security

cloud-socket is designed to provide transport-level security. It encrypts the payload of your messages end-to-end.

However, you are responsible for the initial secure handling of credentials:

  • Authentication: The user's uid and access_token should be obtained through a standard, secure authentication flow (e.g., OAuth, OIDC).
  • Key Management: The crypto_key is a shared secret. You must have a secure way for the client to obtain this key. It should never be hardcoded in the client-side source code. A common pattern is to fetch it from a secure API endpoint after the user has authenticated.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

cloud_socket-0.0.1.tar.gz (17.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

cloud_socket-0.0.1-py3-none-any.whl (12.5 kB view details)

Uploaded Python 3

File details

Details for the file cloud_socket-0.0.1.tar.gz.

File metadata

  • Download URL: cloud_socket-0.0.1.tar.gz
  • Upload date:
  • Size: 17.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.5

File hashes

Hashes for cloud_socket-0.0.1.tar.gz
Algorithm Hash digest
SHA256 a6e95272a31ab31bee5ed1771b072a399add2bc96bbae626fa54978592cca4b6
MD5 3f332a7e1993dcf7a4ceb9860b3826fb
BLAKE2b-256 bcf8673f3eaeb72418c8dcbe9ab8d10ccfa3abed005f71f068a91e6597cf6f75

See more details on using hashes here.

File details

Details for the file cloud_socket-0.0.1-py3-none-any.whl.

File metadata

  • Download URL: cloud_socket-0.0.1-py3-none-any.whl
  • Upload date:
  • Size: 12.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.5

File hashes

Hashes for cloud_socket-0.0.1-py3-none-any.whl
Algorithm Hash digest
SHA256 0f664e6e352634e3383ace869d94f1e4f4c183c87e7ef571f0655b55891ce621
MD5 be873d3f43850a6ba7d50fdf532b1338
BLAKE2b-256 d4abc30e3022171d2ae922c4b415766774ba2c3a9ac66e3e47eac7307604e272

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page