Documentation
¶
Overview ¶
Package adminapi implements the panel JSON API mounted at /api/v1/admin: cookie sessions (auth_tokens kind=web) or personal API tokens (Bearer rdp_..., api_tokens.go), CSRF double-submit (X-CSRF-Token) for cookie sessions, TOTP, OIDC panel login and CRUD for users, groups, devices, address books, audit, identity providers, server control and settings. The contract is api/openapi.yaml; errors use httpx.WriteError ({"error":{"code","message"}}).
Index ¶
- Constants
- func ClientServerSettings(cfg *config.Config, r *http.Request) clientdl.ServerSettings
- func CurrentUser(ctx context.Context) *store.User
- func DecodeRustdeskConfig(s string) (host, relay, api, key string, err error)
- func EncodeRustdeskConfig(host, relay, api, key string) (string, error)
- func OIDCWebLogin(d Deps) oidc.WebLoginFunc
- func Register(r chi.Router, d Deps)
- func RegisterSharePublic(r chi.Router, d Deps, webFS fs.FS)
- func RequireAdmin(next http.Handler) http.Handler
- func RequireUser(next http.Handler) http.Handler
- func SampleOnline(ctx context.Context, st *store.Store, p PresenceReader) error
- func SessionMiddleware(d Deps) func(http.Handler) http.Handler
- func WithSession(ctx context.Context, s *SessionInfo) context.Context
- type ChannelStatus
- type ClientDownloads
- type CommandAudit
- type Deps
- type DeviceKicker
- type DeviceRateInfo
- type EventPublisher
- type IdentityDTO
- type PasskeyDTO
- type PresenceHealth
- type PresenceReader
- type PresenceSource
- type ProviderDTO
- type RelayManager
- type SchemaInfo
- type ServerControl
- type ServerHealthDTO
- type ServerStatusReader
- type SessionInfo
- type SettingsReconciler
- type TOTPService
- type UpdateChecker
- type UserDTO
Constants ¶
const ( // SessionCookie holds the opaque session token (HttpOnly, SameSite=Lax, // Secure when the public URL is https). SessionCookie = "rdpanel_session" // CSRFCookie holds the CSRF token readable by the SPA, echoed back in the // CSRFHeader on every non-GET request. CSRFCookie = "rdpanel_csrf" // CSRFHeader is the double-submit header. CSRFHeader = "X-CSRF-Token" )
Session cookie names shared with the web client (web/src/api/client.ts).
const ( ActionServerCommand = "server.command" // mutating typed call (reconciler, unblock, ...) ActionServerConsole = "server.console" // raw console line )
Admin-audit actions written for admin-channel calls.
const ( LogCaptureFiles = "files" // s6 image: hbbs, hbbr and panel from s6-log dirs LogCapturePanel = "panel" // plain `rdpanel serve`: the panel's own lines only LogCaptureOff = "off" // RDPANEL_LOGS_BUFFER=0 )
Log capture modes reported to the UI.
const ( )
Admin-audit actions of share links.
const ( // SettingShareLinksEnabled turns the feature on. Unset, the configured // RDPANEL_SHARE_LINKS_ENABLED decides, so an existing deployment keeps // whatever it had until someone touches the switch in the panel. )
Panel settings of the public share page (plain text, rendered escaped).
const AppName = "RD Panel"
AppName is the product name shown on the About page.
const DefaultBrandingTitle = "RD Panel"
DefaultBrandingTitle is the panel title when none is configured.
const LogoPath = "/api/v1/admin/branding/logo"
LogoPath is the public URL of the branding logo (relative to the site root).
const MFAPath = "/login"
MFAPath is the SPA route that asks for the second factor after an OIDC login of a user with TOTP enabled ("/login?mfa=1&next=...").
const MinPasswordChars = 8
MinPasswordChars is the minimum length of a password set from the panel.
const PunchCollectorActor = "punch-collector"
PunchCollectorActor names the system actor of the punch-request collector, whose periodic "pr -" is housekeeping and is not audited.
SharePath is where the public share pages are mounted (<base>/s/<token>).
Variables ¶
This section is empty.
Functions ¶
func ClientServerSettings ¶ added in v0.14.0
ClientServerSettings returns the ID server, relay, API URL and public key that RustDesk clients use for this server: RDPANEL_PUBLIC_URL (or, unset, the request's host), the relay public host and hbbs' public key file.
func CurrentUser ¶
CurrentUser returns the fully authenticated user of the request, or nil (anonymous or second factor pending).
func DecodeRustdeskConfig ¶ added in v0.5.0
DecodeRustdeskConfig decodes a RustDesk config string back into its parameters.
func EncodeRustdeskConfig ¶ added in v0.5.0
EncodeRustdeskConfig serializes the connection parameters into RustDesk's URL-safe base64 reversed JSON config string format.
func OIDCWebLogin ¶
func OIDCWebLogin(d Deps) oidc.WebLoginFunc
OIDCWebLogin returns the oidc.WebLoginFunc that turns a successful panel OIDC login into a session (pending second factor when TOTP is enabled). Wire it into oidc.Options.WebLogin.
func Register ¶
Register mounts the admin API on r (already scoped to /api/v1/admin).
Every route gets the CSRF double-submit check (unsafe methods) and the session loader. Resource routes of other streams must be wrapped in RequireUser or RequireAdmin (see session.go).
func RegisterSharePublic ¶ added in v0.14.0
RegisterSharePublic mounts the public share pages at /s on r (the root router, next to /api). webFS is the built SPA (web/dist).
func RequireAdmin ¶
RequireAdmin is RequireUser plus the admin role.
func RequireUser ¶
RequireUser admits fully authenticated users (no pending second factor, no pending forced 2FA enrolment). Mount it on every panel route except the auth and "my security" endpoints.
func SampleOnline ¶
SampleOnline records the current number of online devices into the hourly presence samples (dashboard "online" series). Call it periodically.
func SessionMiddleware ¶
SessionMiddleware returns the session loader for routers mounted outside Register (e.g. /api/v1/events). Combine it with RequireUser/RequireAdmin.
func WithSession ¶
func WithSession(ctx context.Context, s *SessionInfo) context.Context
WithSession returns ctx carrying s (tests of other handler packages).
Types ¶
type ChannelStatus ¶
type ChannelStatus struct {
// Known is false until the channel was probed once.
Known bool
Reachable bool
Since time.Time
RTT time.Duration
LastError string
}
ChannelStatus is the state of one hbbs/hbbr loopback admin channel.
type ClientDownloads ¶ added in v0.13.0
type ClientDownloads interface {
Release(ctx context.Context) clientdl.Result
Open(ctx context.Context, id string) (*os.File, clientdl.Asset, error)
}
ClientDownloads looks up RustDesk releases and keeps verified installer copies (*clientdl.Service).
type CommandAudit ¶
CommandAudit implements control.AuditSink on admin_audit: mutating typed calls become "server.command" rows and raw console lines "server.console" rows (the console handler writes those itself, with an output excerpt). Read-only typed calls are not persisted (they are logged by control).
func NewCommandAudit ¶
func NewCommandAudit(st *store.Store, log *slog.Logger) *CommandAudit
NewCommandAudit returns the sink to install with control.Client.SetAudit.
func (*CommandAudit) RecordCommand ¶
func (a *CommandAudit) RecordCommand(ctx context.Context, rec control.CommandRecord)
RecordCommand implements control.AuditSink.
type Deps ¶
type Deps struct {
Log *slog.Logger
Config *config.Config
Store *store.Store
AEAD *crypto.AEAD
JWT *auth.ClientJWT
Hasher *auth.Hasher
Limiter auth.Limiter
Metrics prometheus.Registerer
// LDAP manages directory synchronization and corporate authentication (nil: disabled).
LDAP *ldap.Service
// WebSessions issues web client session ids bound to panel users (nil: none).
WebSessions *websessions.Registry
// OIDC runs provider flows (nil disables OIDC login/linking).
OIDC *oidc.Service
// TOTP verifies second factors (default: NewTOTPService(Store, AEAD)).
TOTP *TOTPService
// Mail sends e-mail codes and reset links (default: mailauth.New over
// Store, AEAD and Config).
Mail *mailauth.Service
// LoginEvents records login attempts (default: loginlog.DB on Store).
LoginEvents loginlog.Recorder
// Telemetry counts login attempts (nil: no metrics).
Telemetry *metrics.Panel
// Presence reads live device presence (nil: hbbs integration disabled,
// presence falls back to "heartbeat within 45 s").
Presence PresenceReader
// Servers reports the hbbs/hbbr admin channels (nil: unknown).
Servers ServerStatusReader
// Kicks queues heartbeat "disconnect" requests (clientapi.KickQueue).
Kicks DeviceKicker
// Events publishes live events such as device.updated (nil: none).
Events EventPublisher
// DeviceRate is the effective per-IP limit of the unauthenticated device
// endpoints (shown read-only in /settings).
DeviceRate DeviceRateInfo
// ---- stream B2b: address books, audit, server (hbbs/hbbr) ----
// PresenceSrc is the live device presence (nil: devices report offline and
// /server/health reports the heartbeat fallback).
PresenceSrc PresenceSource
// Control is the hbbs/hbbr admin channel (nil: hbbs-backed /server/*
// endpoints answer 503 server_unavailable).
Control ServerControl
// Reconciler owns the desired hbbs/hbbr settings (nil: /server/settings 503).
Reconciler SettingsReconciler
// Relays manages relays and relay agents (nil: /relays/* answer 503).
Relays RelayManager
// Federation manages peering and federated relays (nil: /federation/* answer 503).
Federation *federation.Service
// ClientOptions are the client options pushed in heartbeats (default:
// clientopts.New over Store and AEAD; the app shares one with clientapi).
ClientOptions *clientopts.Service
// ConsoleLimit caps raw console commands per admin per minute (default 30).
ConsoleLimit int
// Logs is the recent log lines buffer behind /server/logs* (nil or
// capacity 0: the endpoints report the buffer as disabled).
Logs *logs.Buffer
// LogSources are the sources the Logs page always lists (with 0 lines).
LogSources []string
// LogCapture is LogCaptureFiles or LogCapturePanel (default).
LogCapture string
// ---- About page (GET /about) ----
// StartedAt is the process start (uptime); zero = when Register ran.
StartedAt time.Time
// Schema reports the applied and the newest embedded migration (nil: unknown).
Schema SchemaInfo
// Updates looks up the latest release (nil: the update check is disabled).
Updates UpdateChecker
// Clients backs the "Install client" page (nil: client downloads are
// disabled; the page then offers only the settings).
Clients ClientDownloads
}
Deps are the collaborators the admin API needs.
type DeviceKicker ¶
DeviceKicker queues a heartbeat "disconnect" for a device (clientapi.KickQueue).
type DeviceRateInfo ¶
DeviceRateInfo is a token bucket: Rate requests per second, bursts of Burst.
type EventPublisher ¶
EventPublisher publishes live events (*events.Bus).
type IdentityDTO ¶
type IdentityDTO struct {
ID int64 `json:"id"`
ProviderID int64 `json:"provider_id"`
ProviderSlug string `json:"provider_slug"`
ProviderKind string `json:"provider_kind"`
ProviderName string `json:"provider_name"`
Subject string `json:"subject"`
Email *string `json:"email"`
EmailVerified bool `json:"email_verified"`
Username *string `json:"username"`
DisplayName string `json:"display_name"`
AvatarURL string `json:"avatar_url"`
LastLoginAt *time.Time `json:"last_login_at"`
CreatedAt time.Time `json:"created_at"`
}
IdentityDTO is components.schemas.UserIdentity (a linked IdP identity), used by /me/security/identities and the admin user detail.
func IdentitiesOf ¶
IdentitiesOf lists a user's linked identities as API objects (also for the admin users page).
type PasskeyDTO ¶
type PasskeyDTO struct {
ID int64 `json:"id"`
Name string `json:"name"`
CreatedAt time.Time `json:"created_at"`
LastUsedAt *time.Time `json:"last_used_at"`
BackupEligible bool `json:"backup_eligible"`
Synced bool `json:"synced"`
CloneWarning bool `json:"clone_warning"`
Transports []string `json:"transports"`
}
PasskeyDTO is components.schemas.Passkey.
type PresenceHealth ¶
type PresenceHealth struct {
// Polls counts poll cycles since start (0 = no observation yet).
Polls uint64
Reachable bool
// Since is when Reachable last changed.
Since time.Time
// LastOK is the last successful poll.
LastOK time.Time
RTT time.Duration
LastError string
}
PresenceHealth is the presence poller's view of hbbs (rendezvous port).
type PresenceReader ¶
type PresenceReader interface {
// OnlineIDs returns the RustDesk IDs currently online.
OnlineIDs() []string
// DevicePresence returns the state of one device; known is false when the
// poller has not observed it yet.
DevicePresence(rustdeskID string) (online bool, since time.Time, known bool)
PresenceHealth() PresenceHealth
}
PresenceReader exposes live device presence (implemented over hbbs/presence.Poller in internal/app).
type PresenceSource ¶
PresenceSource is the live device presence (implemented by *presence.Poller).
type ProviderDTO ¶
type ProviderDTO struct {
ID int64 `json:"id"`
Slug string `json:"slug"`
Kind string `json:"kind"`
DisplayName string `json:"display_name"`
ClientID string `json:"client_id"`
HasClientSecret bool `json:"has_client_secret"`
Issuer *string `json:"issuer"`
Scopes []string `json:"scopes"`
PKCEEnabled bool `json:"pkce_enabled"`
PKCEMethod string `json:"pkce_method"`
AutoRegister bool `json:"auto_register"`
LinkByVerifiedEmail bool `json:"link_by_verified_email"`
Enabled bool `json:"enabled"`
SortOrder int `json:"sort_order"`
CallbackURL string `json:"callback_url"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
ProviderDTO is components.schemas.IdentityProvider. The client secret is write-only: only has_client_secret is returned.
type RelayManager ¶ added in v0.3.0
type RelayManager interface {
List(ctx context.Context) ([]relays.View, relays.Rotation, error)
Get(ctx context.Context, id int64) (relays.View, error)
Observed(ctx context.Context) ([]string, error)
Create(ctx context.Context, in relays.CreateInput) (relays.View, *relays.Enrollment, error)
Update(ctx context.Context, id int64, p relays.Patch) (relays.View, error)
Delete(ctx context.Context, id int64) error
ResetEnrollment(ctx context.Context, id int64) (*relays.Enrollment, error)
Approve(ctx context.Context, id int64, by *int64) (relays.View, error)
Revoke(ctx context.Context, id int64) (relays.View, error)
ProbeNow(ctx context.Context, id int64) (relays.View, error)
Settings(ctx context.Context, id int64) (relays.SettingsView, error)
SaveSettings(ctx context.Context, id int64, ov reconcile.Settings, by *int64) (relays.SettingsView, error)
Usage(ctx context.Context, id int64) ([]control.RelayUsage, error)
Traffic(ctx context.Context, id int64, since time.Time) ([]relays.TrafficSample, error)
GetOptions(ctx context.Context) (relays.Options, error)
SetOptions(ctx context.Context, o relays.Options, by *int64) error
HBBSKeyFingerprint() string
ListPrefixRules(ctx context.Context) ([]relays.PrefixRule, error)
CreatePrefixRule(ctx context.Context, rule *relays.PrefixRule) error
DeletePrefixRule(ctx context.Context, id int64) error
ImportCountryRules(ctx context.Context, countryCode, relayHost, customComment string) (*relays.ImportCountryRulesResult, error)
GeoIP() *relays.GeoIPEngine
}
RelayManager is implemented by *relays.Service.
type SchemaInfo ¶
type SchemaInfo interface {
SchemaVersion(ctx context.Context) (int64, error)
LatestSchemaVersion() (int64, error)
}
SchemaInfo reports the database schema version (implemented by *db.DB).
type ServerControl ¶
type ServerControl interface {
Addr(t control.Target) string
ExecLine(ctx context.Context, t control.Target, line string) (string, error)
IPBlocker(ctx context.Context, start int) (control.IPBlockerPage, error)
IPBlockerLookup(ctx context.Context, ip string, remove bool) (*control.IPBlockerEntry, error)
IPChanges(ctx context.Context, start int) (control.IPChangesPage, error)
IPChangesLookup(ctx context.Context, id string, remove bool) (*control.IPChange, error)
Usage(ctx context.Context) ([]control.RelayUsage, error)
}
ServerControl is the hbbs/hbbr admin channel (implemented by *control.Client).
type ServerHealthDTO ¶
type ServerHealthDTO struct {
HBBS componentHealthDTO `json:"hbbs"`
HBBR componentHealthDTO `json:"hbbr"`
Presence presenceHealthDTO `json:"presence"`
SettingsInSync *bool `json:"settings_in_sync,omitempty"`
}
ServerHealthDTO is components.schemas.ServerHealth.
type ServerStatusReader ¶
type ServerStatusReader interface {
ChannelStatus() (hbbs, hbbr ChannelStatus)
// SettingsInSync reports whether every desired setting was applied.
SettingsInSync(ctx context.Context) (bool, error)
}
ServerStatusReader exposes the reconciler's view of hbbs/hbbr.
type SessionInfo ¶
type SessionInfo struct {
Token *store.AuthToken
User *store.User
// MFAPending: password accepted, TOTP/recovery code still owed.
MFAPending bool
// TOTPEnabled: the user has confirmed TOTP.
TOTPEnabled bool
// MustEnrollTOTP: policy requires 2FA but the user has not enrolled; only
// the auth and "my security" endpoints are reachable.
MustEnrollTOTP bool
// APIToken is set when the request authenticated with a personal API
// token (Authorization: Bearer rdp_...) instead of the session cookie.
// Token is then a placeholder with ID 0 that matches no auth_tokens row.
APIToken *store.APIToken
}
SessionInfo describes the authenticated panel session of a request.
func CurrentSession ¶
func CurrentSession(ctx context.Context) *SessionInfo
CurrentSession returns the request's session (nil when anonymous).
type SettingsReconciler ¶
type SettingsReconciler interface {
Status() reconcile.Status
Desired(ctx context.Context) (reconcile.Settings, error)
KeyStatus(ctx context.Context) ([]reconcile.KeyStatus, error)
Current(ctx context.Context) (reconcile.Observed, error)
Apply(ctx context.Context, s reconcile.Settings, updatedBy *int64) error
Reconcile(ctx context.Context) error
}
SettingsReconciler owns the desired hbbs/hbbr settings (implemented by *reconcile.Reconciler).
type TOTPService ¶
type TOTPService struct {
// contains filtered or unexported fields
}
TOTPService verifies and manages TOTP second factors and recovery codes. It satisfies the client API's TOTPVerifier (POST /api/login tfa step):
Enrolled(ctx, userID uint32) (bool, error) Verify(ctx, userID uint32, code string) (bool, error)
func NewTOTPService ¶
func NewTOTPService(st *store.Store, aead *crypto.AEAD) *TOTPService
NewTOTPService returns a TOTPService.
func (*TOTPService) ResetUser ¶
func (t *TOTPService) ResetUser(ctx context.Context, userID int64) error
ResetUser removes a user's 2FA (admin "force 2FA reset"; for stream B2/CLI).
type UpdateChecker ¶
type UpdateChecker interface {
Latest(ctx context.Context) updatecheck.Result
}
UpdateChecker returns the cached latest release (*updatecheck.Checker).
type UserDTO ¶
type UserDTO struct {
ID int64 `json:"id"`
Username string `json:"username"`
Email *string `json:"email"`
DisplayName string `json:"display_name"`
AvatarURL string `json:"avatar_url"`
Note string `json:"note"`
Role store.Role `json:"role"`
Status string `json:"status"`
UserGroupID *int64 `json:"user_group_id"`
HasPassword bool `json:"has_password"`
TOTPEnabled bool `json:"totp_enabled"`
TOTPRequired bool `json:"totp_required"`
EmailVerified bool `json:"email_verified"`
Email2FAEnabled bool `json:"email_2fa_enabled"`
IsLDAP bool `json:"is_ldap"`
LastLoginAt *time.Time `json:"last_login_at"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
UserDTO is the API representation of a user (components.schemas.User).
Source Files
¶
- about.go
- acl.go
- acl_policy.go
- adminapi.go
- api_tokens.go
- auth.go
- auth_dto.go
- auth_email.go
- auth_providers.go
- auth_security.go
- auth_totp.go
- b2b.go
- b2b_audit.go
- b2b_books.go
- b2b_client_options.go
- b2b_server.go
- clients.go
- control_roles.go
- dashboard.go
- devices.go
- federation.go
- groups.go
- ldap.go
- passkeys.go
- relays.go
- resources.go
- server_logs.go
- session.go
- session_csrf.go
- settings.go
- share_links.go
- share_public.go
- strategies.go
- users.go
- webclient.go
- webclient_shells.go