package environment import ( "context" "encoding/json" "fmt" ) // CreateStandaloneEnv creates only a browser environment; no social account or // login profile exists until the browser's first verified login. func (s *Store) CreateStandaloneEnv(ctx context.Context, gateway string, fingerprint Fingerprint) (EnvironmentContext, error) { if !gatewayNamePattern.MatchString(gateway) || fingerprint.Seed != 0 || fingerprint.ProxyServer != "" || fingerprint.Validate() != nil { return EnvironmentContext{}, ErrInvalid } alias := "env-" + newHubID() encoded, err := json.Marshal(fingerprint) if err != nil { return EnvironmentContext{}, fmt.Errorf("encode browser fingerprint: %w", err) } if err := s.db.QueryRowContext(ctx, `INSERT INTO browser_env(alias,name,gateway_id,fingerprint,profile_id) SELECT $1,$1,id,jsonb_set($3::jsonb,'{seed}',to_jsonb(nextval('browser_fingerprint_seed_seq'))),$1 FROM gateway WHERE name=$2 RETURNING alias`, alias, gateway, encoded).Scan(&alias); err != nil { return EnvironmentContext{}, rowError(err) } return s.GetEnvironmentContext(ctx, alias) } func (s *Store) ListPendingEnvironments(ctx context.Context) ([]EnvironmentContext, error) { rows, err := s.db.QueryContext(ctx, `SELECT alias FROM browser_env WHERE account_id IS NULL ORDER BY id DESC`) if err != nil { return nil, fmt.Errorf("list pending browser environments: %w", err) } aliases := []string{} for rows.Next() { var alias string if err := rows.Scan(&alias); err != nil { rows.Close() return nil, err } aliases = append(aliases, alias) } err = rows.Err() rows.Close() if err != nil { return nil, err } result := make([]EnvironmentContext, 0, len(aliases)) for _, alias := range aliases { env, err := s.GetEnvironmentContext(ctx, alias) if err != nil { return nil, err } result = append(result, env) } return result, nil }