auth

package
v0.3.4 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 24, 2026 License: Apache-2.0 Imports: 19 Imported by: 0

Documentation

Overview

Package auth implements the cryptographic primitives used by the asobi-cli device-code login flow.

Protocol: clean-room reimplementation of the Supabase CLI device login using standard primitives (NIST SP 800-56A for ECDH key agreement on P-256, RFC 5869 HKDF-SHA256 for key derivation, NIST SP 800-38D AES-256-GCM for authenticated encryption).

The CLI generates an ephemeral P-256 keypair and sends its public key to asobi_saas. The saas side generates its own ephemeral keypair, derives the ECDH shared secret, encrypts the issued API key with AES-256-GCM, and returns the ciphertext plus its public key. The CLI recomputes the shared secret from its private key and the saas public key, then decrypts.

The Erlang counterpart lives in asobi_saas_cli_crypto. Both sides use the same HKDF info string ("asobi-cli-device-login-v1") and an empty salt to maintain domain-separation across future versions.

Index

Constants

View Source
const HKDFInfo = "asobi-cli-device-login-v1"

HKDFInfo is the domain-separated info string used by HKDF-SHA256. Must match the ?INFO macro in asobi_saas_cli_crypto.erl exactly.

Variables

This section is empty.

Functions

func CreateEnv

func CreateEnv(creds *Credentials, game, name, size string) (map[string]interface{}, error)

CreateEnv creates a named environment for a game with a given size.

func Decrypt

func Decrypt(ciphertext, tag, nonce, key []byte) ([]byte, error)

Decrypt opens a ciphertext with AES-256-GCM using the given key, nonce, and tag. Returns an error if the tag does not verify (tamper detection) or if the key length or nonce length is wrong.

func DeleteCredentials

func DeleteCredentials() error

DeleteCredentials removes the stored credentials file.

func DeleteEnv

func DeleteEnv(creds *Credentials, game, name string) error

DeleteEnv deletes a named environment within a game.

func DeployBundle

func DeployBundle(creds *Credentials, game, name string, bundle []byte) (map[string]interface{}, error)

DeployBundle uploads a zip bundle to a named environment within a game.

func DeriveSharedSecret

func DeriveSharedSecret(peerPublic, ownPrivate []byte) ([]byte, error)

DeriveSharedSecret runs ECDH between a peer public key and our own private key, then stretches the raw shared secret into a 32-byte AES-256 key via HKDF-SHA256 with a fixed empty salt and the asobi-specific info string.

func Destroy

func Destroy(creds *Credentials, envID string) error

Destroy deletes an environment by ID. Idempotent.

func DeviceFingerprint

func DeviceFingerprint() string

DeviceFingerprint returns a stable identifier for this machine.

func Encrypt

func Encrypt(plaintext, key []byte) (nonce, ciphertext, tag []byte, err error)

Encrypt seals a plaintext with AES-256-GCM. The caller supplies a 32-byte key (typically the output of DeriveSharedSecret). A fresh 12-byte random nonce is generated per call. Returns (nonce, ciphertext, tag) as three separate byte slices so the wire format matches the Erlang side's encrypt/2 return shape.

func EnvAction

func EnvAction(creds *Credentials, game, name, action string) error

EnvAction performs stop/start on a named environment within a game.

func ListEnvs2

func ListEnvs2(creds *Credentials, game string) ([]map[string]interface{}, error)

ListEnvs2 returns environments for a game using the new flat model.

func RefreshAccessToken

func RefreshAccessToken(creds *Credentials) (string, error)

RefreshAccessToken exchanges a refresh token for a new access token. The device secret issued at login must match the hash stored server-side.

func ResizeEnv

func ResizeEnv(creds *Credentials, game, name, size string) error

ResizeEnv changes the size of a named environment within a game.

func SaveCredentials

func SaveCredentials(creds *Credentials) error

SaveCredentials writes credentials to disk with 0600 permissions.

Types

type Credentials

type Credentials struct {
	AccessToken       string `json:"access_token"`
	RefreshToken      string `json:"refresh_token"`
	SaasURL           string `json:"saas_url"`
	EngineURL         string `json:"engine_url"`
	TenantID          string `json:"tenant_id"`
	GameID            string `json:"game_id"`
	EnvironmentID     string `json:"environment_id"`
	EnvName           string `json:"env_name"`
	DeviceFingerprint string `json:"device_fingerprint"`
	// DeviceSecret is the server-issued secret that binds the refresh token
	// to this CLI install. Presented on refresh; never sent anywhere else.
	DeviceSecret string `json:"device_secret"`
	// ActiveGame is the slug of the game selected via `asobi use <slug>`.
	// The effective game for env operations resolves from --game, then this.
	ActiveGame string `json:"active_game"`
}

Credentials holds the CLI's saas session tokens and associated context. Stored in ~/.asobi/credentials.json with 0600 permissions. On Windows, where the file mode does not create an ACL, the blob is additionally encrypted at rest with DPAPI scoped to the current user (see protect).

func LoadCredentials

func LoadCredentials() (*Credentials, error)

LoadCredentials reads the stored CLI credentials. Returns nil if no credentials exist (not an error — user hasn't logged in yet). The ASOBI_ACCESS_TOKEN env var overrides the stored access token.

func Login

func Login(saasURL, tokenName string) (*Credentials, error)

Login runs the full ECDH-encrypted device-code login flow. It returns credentials on success or an error.

type Environment

type Environment struct {
	ID          string `json:"id"`
	Name        string `json:"name"`
	Status      string `json:"status"`
	IsEphemeral bool   `json:"is_ephemeral"`
	ExpiresAt   string `json:"expires_at"`
	InsertedAt  string `json:"inserted_at"`
}

Environment is a single env returned by ListEnvs.

func ListEnvs

func ListEnvs(creds *Credentials, ephemeralOnly bool) ([]Environment, error)

ListEnvs returns all environments for the current game. If ephemeralOnly is true, only ephemeral envs are returned.

type Game

type Game struct {
	ID   string `json:"id"`
	Slug string `json:"slug"`
	Name string `json:"name"`
}

Game is a single game returned by ListGames.

func ListGames

func ListGames(creds *Credentials) ([]Game, error)

ListGames returns the games belonging to the caller's tenant.

type Keypair

type Keypair struct {
	Public  []byte
	Private []byte
}

Keypair holds a raw P-256 public key (65 bytes, uncompressed SEC1) and its corresponding private scalar (32 bytes).

func GenerateKeypair

func GenerateKeypair() (*Keypair, error)

GenerateKeypair produces a fresh ephemeral P-256 keypair.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL