Documentation
¶
Overview ¶
Package domain holds the entities shared by every layer of the panel.
Index ¶
- Variables
- type APIToken
- type Admin
- type AdminRole
- type Announcement
- type AnnouncementLevel
- type BillingCycle
- type ChannelKind
- type ConfigProfile
- type ConfigProfileInbound
- type Device
- type Event
- type EventKind
- type Host
- type Node
- type NodeHealth
- type NodeMetric
- type NodeUsageSample
- type NotificationChannel
- type NotificationDelivery
- type ProfileKind
- type Settings
- type Squad
- type TrafficResetStrategy
- type User
- type UserStatus
- type UserUsageSample
Constants ¶
This section is empty.
Variables ¶
var AllEventKinds = []EventKind{ EventNodeConnected, EventNodeDisconnected, EventNodeConfigPushed, EventNodeError, EventUserCreated, EventUserUpdated, EventUserDeleted, EventUserLimited, EventUserExpired, EventUserExpiringSoon, EventUserQuotaWarning, EventAdminLogin, EventAdminLoginFailed, EventAdminSecurity, EventAdminLocked, EventProfileUpdated, EventNodePaymentDue, EventDeviceBlocked, EventSettingsUpdated, }
AllEventKinds is the list a channel picks its subscriptions from, and the list the UI renders. Keeping it beside the constants means a new event kind is subscribable the moment it exists.
Functions ¶
This section is empty.
Types ¶
type APIToken ¶
type APIToken struct {
UUID string `json:"uuid"`
Name string `json:"name"`
TokenHash string `json:"-"`
Preview string `json:"tokenPreview"`
CreatedBy string `json:"createdBy"`
LastUsedAt *time.Time `json:"lastUsedAt"`
ExpiresAt *time.Time `json:"expiresAt"`
CreatedAt time.Time `json:"createdAt"`
}
APIToken authenticates an external integration against the panel API.
type Admin ¶
type Admin struct {
UUID string `json:"uuid"`
Username string `json:"username"`
PasswordHash string `json:"-"`
Role AdminRole `json:"role"`
IsDisabled bool `json:"isDisabled"`
LastLoginAt *time.Time `json:"lastLoginAt"`
CreatedAt time.Time `json:"createdAt"`
UpdatedAt time.Time `json:"updatedAt"`
// Two-factor. The secret and the recovery digests never leave the panel —
// TOTPEnabled is all the UI needs, and anything more would put a working
// second factor into every response that carries an administrator.
TOTPSecret string `json:"-"`
TOTPEnabled bool `json:"totpEnabled"`
TOTPConfirmedAt *time.Time `json:"totpConfirmedAt"`
TOTPLastStep int64 `json:"-"`
RecoveryCodeHashes []string `json:"-"`
// A count, never the codes: an operator needs to know they are running low,
// and nothing more can be given back once they have been shown.
RecoveryCodesLeft int `json:"recoveryCodesLeft"`
}
type AdminRole ¶
type AdminRole string
type Announcement ¶ added in v0.2.0
type Announcement struct {
UUID string `json:"uuid"`
Title string `json:"title"`
Body string `json:"body"`
Level AnnouncementLevel `json:"level"`
IsEnabled bool `json:"isEnabled"`
StartsAt *time.Time `json:"startsAt"`
EndsAt *time.Time `json:"endsAt"`
CreatedAt time.Time `json:"createdAt"`
UpdatedAt time.Time `json:"updatedAt"`
}
Announcement is a notice shown to subscribers on their subscription page.
type AnnouncementLevel ¶ added in v0.2.0
type AnnouncementLevel string
AnnouncementLevel tints the notice on the subscription page.
const ( AnnouncementInfo AnnouncementLevel = "INFO" AnnouncementWarning AnnouncementLevel = "WARNING" AnnouncementDanger AnnouncementLevel = "DANGER" )
func (AnnouncementLevel) Valid ¶ added in v0.2.0
func (l AnnouncementLevel) Valid() bool
type BillingCycle ¶
type BillingCycle string
BillingCycle is how often a node has to be paid for.
const ( BillingNone BillingCycle = "NONE" BillingMonthly BillingCycle = "MONTHLY" BillingQuarterly BillingCycle = "QUARTERLY" BillingYearly BillingCycle = "YEARLY" )
func (BillingCycle) Advance ¶
func (c BillingCycle) Advance(from time.Time) time.Time
Advance returns the next payment date one cycle after the given one.
func (BillingCycle) MonthlyCost ¶
func (c BillingCycle) MonthlyCost(amount float64) float64
MonthlyCost normalises a billing cycle onto a monthly figure so nodes on different cycles can be summed.
func (BillingCycle) Valid ¶
func (c BillingCycle) Valid() bool
type ChannelKind ¶ added in v0.2.0
type ChannelKind string
ChannelKind is how a notification leaves the panel.
const ( ChannelWebhook ChannelKind = "WEBHOOK" ChannelTelegram ChannelKind = "TELEGRAM" )
func (ChannelKind) Valid ¶ added in v0.2.0
func (k ChannelKind) Valid() bool
type ConfigProfile ¶
type ConfigProfile struct {
UUID string `json:"uuid"`
Name string `json:"name"`
// Kind decides which engine validates and renders this document. Empty
// reads as xray, so every profile written before this existed is correct.
Kind ProfileKind `json:"kind"`
Config json.RawMessage `json:"config"`
CreatedAt time.Time `json:"createdAt"`
UpdatedAt time.Time `json:"updatedAt"`
Inbounds []ConfigProfileInbound `json:"inbounds,omitempty"`
NodeIDs []string `json:"nodeUuids,omitempty"`
}
type ConfigProfileInbound ¶
type ConfigProfileInbound struct {
UUID string `json:"uuid"`
ConfigProfileID string `json:"profileUuid"`
ProfileName string `json:"profileName,omitempty"`
Tag string `json:"tag"`
Type string `json:"type"`
Network string `json:"network"`
Security string `json:"security"`
Port int `json:"port"`
}
ConfigProfileInbound mirrors one inbound of the profile document. It is extracted on save so squads and hosts can reference inbounds by identity instead of by fragile string tags.
type Device ¶
type Device struct {
UserID string `json:"userUuid"`
// Username is filled by the cross-user inspector so the list is readable
// without a lookup per row.
Username string `json:"username,omitempty"`
HWID string `json:"hwid"`
UserAgent string `json:"userAgent"`
Platform string `json:"platform"`
FirstSeen time.Time `json:"firstSeen"`
LastSeen time.Time `json:"lastSeen"`
}
Device is one client seen on a user's subscription.
type EventKind ¶
type EventKind string
EventKind classifies audit log records.
const ( EventNodeConnected EventKind = "NODE_CONNECTED" EventNodeDisconnected EventKind = "NODE_DISCONNECTED" EventNodeConfigPushed EventKind = "NODE_CONFIG_PUSHED" EventNodeError EventKind = "NODE_ERROR" EventUserCreated EventKind = "USER_CREATED" EventUserUpdated EventKind = "USER_UPDATED" EventUserDeleted EventKind = "USER_DELETED" EventUserLimited EventKind = "USER_LIMITED" EventUserExpired EventKind = "USER_EXPIRED" // Sent before the fact rather than after, so an operator or a billing // system can act while the subscriber still has service. EventUserExpiringSoon EventKind = "USER_EXPIRING_SOON" EventUserQuotaWarning EventKind = "USER_QUOTA_WARNING" EventAdminLogin EventKind = "ADMIN_LOGIN" EventAdminLoginFailed EventKind = "ADMIN_LOGIN_FAILED" // A second factor being turned on or off, and a sign-in locked for // repeated failures — both are worth waking someone up for. EventAdminSecurity EventKind = "ADMIN_SECURITY" EventAdminLocked EventKind = "ADMIN_LOCKED" EventProfileUpdated EventKind = "PROFILE_UPDATED" EventNodePaymentDue EventKind = "NODE_PAYMENT_DUE" EventDeviceBlocked EventKind = "DEVICE_LIMIT_REACHED" EventSettingsUpdated EventKind = "SETTINGS_UPDATED" )
type Host ¶
type Host struct {
UUID string `json:"uuid"`
InboundID string `json:"inboundUuid"`
InboundTag string `json:"inboundTag,omitempty"`
InboundType string `json:"inboundType,omitempty"`
ProfileID string `json:"configProfileUuid,omitempty"`
ProfileName string `json:"configProfileName,omitempty"`
Remark string `json:"remark"`
Address string `json:"address"`
Port int `json:"port"`
Path string `json:"path"`
SNI string `json:"sni"`
HostHeader string `json:"hostHeader"`
ALPN string `json:"alpn"`
Fingerprint string `json:"fingerprint"`
PublicKey string `json:"publicKey"`
ShortID string `json:"shortId"`
SpiderX string `json:"spiderX"`
Flow string `json:"flow"`
Security string `json:"security"`
AllowInsecure bool `json:"allowInsecure"`
Tags []string `json:"tags"`
IsDisabled bool `json:"isDisabled"`
ViewPosition int `json:"viewPosition"`
CreatedAt time.Time `json:"createdAt"`
UpdatedAt time.Time `json:"updatedAt"`
}
Host is a client-facing entry point advertised in subscriptions. It points at one inbound of a config profile but may carry its own address/SNI/etc so a single inbound can be published behind many domains or CDNs.
type Node ¶
type Node struct {
UUID string `json:"uuid"`
Name string `json:"name"`
Address string `json:"address"`
CountryCode string `json:"countryCode"`
Description string `json:"description"`
TokenHash string `json:"-"`
// TokenPreview keeps the last characters of the enrolment token so the UI can
// tell two nodes apart without ever exposing the secret again.
TokenPreview string `json:"tokenPreview"`
IsDisabled bool `json:"isDisabled"`
Health NodeHealth `json:"health"`
ConfigProfileID *string `json:"configProfileUuid"`
ConfigProfileName string `json:"configProfileName,omitempty"`
ActiveInboundTags []string `json:"activeInboundTags"`
ConsumptionMultip float64 `json:"consumptionMultiplier"`
TrafficLimitBytes int64 `json:"trafficLimitBytes"`
TrafficUsedBytes int64 `json:"trafficUsedBytes"`
TrafficResetPolicy TrafficResetStrategy `json:"trafficResetStrategy"`
NotifyPercent int `json:"notifyPercent"`
LastTrafficResetAt *time.Time `json:"lastTrafficResetAt"`
AgentVersion string `json:"agentVersion"`
XrayVersion string `json:"xrayVersion"`
XrayRunning bool `json:"xrayRunning"`
XrayStartedAt *time.Time `json:"xrayStartedAt"`
ConfigHash string `json:"configHash"`
Hostname string `json:"hostname"`
OS string `json:"os"`
Arch string `json:"arch"`
Kernel string `json:"kernel"`
CPUCount int `json:"cpuCount"`
CPUModel string `json:"cpuModel"`
CPUUsage float64 `json:"cpuUsagePercent"`
TotalRAMBytes int64 `json:"totalRamBytes"`
UsedRAMBytes int64 `json:"usedRamBytes"`
LoadAvg1 float64 `json:"loadAvg1"`
OnlineUsers int `json:"onlineUsers"`
// Infrastructure billing: what this node costs and who it is rented from.
Provider string `json:"provider"`
ProviderURL string `json:"providerUrl"`
CostAmount float64 `json:"costAmount"`
CostCurrency string `json:"costCurrency"`
BillingCycle BillingCycle `json:"billingCycle"`
NextPaymentAt *time.Time `json:"nextPaymentAt"`
BillingNotes string `json:"billingNotes"`
Tags []string `json:"tags"`
StatusMessage string `json:"statusMessage"`
LastStatusAt *time.Time `json:"lastStatusChangeAt"`
LastConnectedAt *time.Time `json:"lastConnectedAt"`
ViewPosition int `json:"viewPosition"`
CreatedAt time.Time `json:"createdAt"`
UpdatedAt time.Time `json:"updatedAt"`
}
Node is a server running the agent and an xray-core process.
type NodeHealth ¶
type NodeHealth string
const ( NodeHealthUnknown NodeHealth = "UNKNOWN" NodeHealthConnecting NodeHealth = "CONNECTING" NodeHealthOnline NodeHealth = "ONLINE" NodeHealthDegraded NodeHealth = "DEGRADED" NodeHealthOffline NodeHealth = "OFFLINE" NodeHealthDisabled NodeHealth = "DISABLED" NodeHealthTrafficLimit NodeHealth = "TRAFFIC_LIMITED" )
type NodeMetric ¶ added in v0.2.0
type NodeMetric struct {
At time.Time `json:"at"`
CPUPercent float64 `json:"cpuPercent"`
UsedRAM int64 `json:"usedRamBytes"`
TotalRAM int64 `json:"totalRamBytes"`
LoadAvg1 float64 `json:"loadAvg1"`
OnlineUsers int `json:"onlineUsers"`
}
NodeMetric is one heartbeat sample, kept so load can be read as a trend.
type NodeUsageSample ¶
type NodeUsageSample struct {
NodeID string `json:"nodeUuid"`
NodeName string `json:"nodeName,omitempty"`
At time.Time `json:"at"`
Bytes int64 `json:"bytes"`
}
NodeUsageSample is one bucketed traffic measurement for a node.
type NotificationChannel ¶ added in v0.2.0
type NotificationChannel struct {
UUID string `json:"uuid"`
Name string `json:"name"`
Kind ChannelKind `json:"kind"`
Config json.RawMessage `json:"config"`
// Empty subscribes to everything, which is what most deployments want and
// avoids a channel that silently delivers nothing.
Events []EventKind `json:"events"`
IsEnabled bool `json:"isEnabled"`
LastOK *bool `json:"lastOk"`
LastDetail string `json:"lastDetail"`
LastSentAt *time.Time `json:"lastSentAt"`
CreatedAt time.Time `json:"createdAt"`
UpdatedAt time.Time `json:"updatedAt"`
}
NotificationChannel is one destination events are delivered to. Config holds the transport-specific fields — a URL and signing secret, or a bot token and chat id — so adding a transport does not mean adding columns.
func (NotificationChannel) Wants ¶ added in v0.2.0
func (c NotificationChannel) Wants(kind EventKind) bool
Wants reports whether this channel should receive an event.
type NotificationDelivery ¶ added in v0.2.0
type NotificationDelivery struct {
ID int64 `json:"id"`
ChannelID string `json:"channelUuid"`
EventKind EventKind `json:"eventKind"`
OK bool `json:"ok"`
Detail string `json:"detail"`
Attempts int `json:"attempts"`
DurationMS int `json:"durationMs"`
CreatedAt time.Time `json:"createdAt"`
}
NotificationDelivery is one attempt to reach a channel, kept so "the webhook never arrived" is an answerable question.
type ProfileKind ¶ added in v0.11.0
type ProfileKind string
ConfigProfile is a reusable xray-core configuration document. Nodes are bound to exactly one profile and serve a subset of its inbounds. ProfileKind names the engine a profile's document is written for.
const ( ProfileXray ProfileKind = "xray" ProfileHysteria2 ProfileKind = "hysteria2" ProfileSingBox ProfileKind = "singbox" )
func (ProfileKind) Valid ¶ added in v0.11.0
func (k ProfileKind) Valid() bool
type Settings ¶
type Settings struct {
BrandName string `json:"brandName"`
BrandTagline string `json:"brandTagline"`
BrandLogo string `json:"brandLogo"`
BrandAccent string `json:"brandAccent"`
SubscriptionTitle string `json:"subscriptionTitle"`
SupportURL string `json:"supportUrl"`
Currency string `json:"currency"`
// SubscriptionFormat is what an unrecognised client is served. Empty keeps
// the base64 list, which every client can read. Clients that announce
// themselves — Clash, sing-box — still get their own format regardless.
SubscriptionFormat string `json:"subscriptionFormat"`
// What the subscriber's page offers. Both default to on, so an existing
// deployment looks exactly as it did.
SubPageShowLinks bool `json:"subPageShowLinks"`
SubPageShowFormats bool `json:"subPageShowFormats"`
// Custom documents for the two formats that are whole config files rather
// than a list of links. Empty means the built-in template.
ClashTemplate string `json:"clashTemplate"`
SingBoxTemplate string `json:"singboxTemplate"`
// RequireTOTP refuses a session to any administrator without a second
// factor, sending them to enrolment instead.
RequireTOTP bool `json:"requireTotp"`
// How early to warn. Zero disables either warning, which is what every
// install did before these existed.
WarnExpiryDays int `json:"warnExpiryDays"`
WarnQuotaPercent int `json:"warnQuotaPercent"`
UpdatedAt time.Time `json:"updatedAt"`
}
Settings holds the panel-wide knobs an operator can change at runtime, including white-label branding for corporate deployments.
type Squad ¶
type Squad struct {
UUID string `json:"uuid"`
Name string `json:"name"`
Info string `json:"info"`
CreatedAt time.Time `json:"createdAt"`
UpdatedAt time.Time `json:"updatedAt"`
InboundIDs []string `json:"inboundUuids"`
Inbounds []ConfigProfileInbound `json:"inbounds,omitempty"`
MemberCount int `json:"membersCount"`
}
Squad groups inbounds together; users are attached to squads rather than to individual inbounds, which keeps bulk membership changes cheap.
type TrafficResetStrategy ¶
type TrafficResetStrategy string
const ( ResetNever TrafficResetStrategy = "NO_RESET" ResetDay TrafficResetStrategy = "DAY" ResetWeek TrafficResetStrategy = "WEEK" ResetMonth TrafficResetStrategy = "MONTH" )
func (TrafficResetStrategy) Valid ¶
func (s TrafficResetStrategy) Valid() bool
type User ¶
type User struct {
UUID string `json:"uuid"`
ShortUUID string `json:"shortUuid"`
Username string `json:"username"`
SubscriptionUUID string `json:"subscriptionUuid"`
VlessUUID string `json:"vlessUuid"`
TrojanPassword string `json:"trojanPassword"`
SSPassword string `json:"ssPassword"`
Status UserStatus `json:"status"`
TrafficLimitBytes int64 `json:"trafficLimitBytes"`
UsedTrafficBytes int64 `json:"usedTrafficBytes"`
LifetimeTrafficBytes int64 `json:"lifetimeUsedTrafficBytes"`
TrafficResetPolicy TrafficResetStrategy `json:"trafficLimitStrategy"`
LastTrafficResetAt *time.Time `json:"lastTrafficResetAt"`
ExpireAt *time.Time `json:"expireAt"`
OnlineAt *time.Time `json:"onlineAt"`
Description string `json:"description"`
Tag string `json:"tag"`
Email string `json:"email"`
TelegramID *int64 `json:"telegramId"`
HWIDDeviceLimit int `json:"hwidDeviceLimit"`
SubLastUA string `json:"subLastUserAgent"`
SubLastOpenedAt *time.Time `json:"subLastOpenedAt"`
SubRevokedAt *time.Time `json:"subRevokedAt"`
CreatedAt time.Time `json:"createdAt"`
UpdatedAt time.Time `json:"updatedAt"`
SquadIDs []string `json:"squadUuids"`
Squads []Squad `json:"squads,omitempty"`
// WireGuard needs a key pair per subscriber rather than a shared secret.
// The private half is stored because the panel is what hands out the
// .conf; only the public half ever reaches a node.
WGPrivateKey string `json:"-"`
WGPublicKey string `json:"-"`
// A stable number the tunnel address is derived from, so an address never
// moves under a subscriber who already imported their configuration.
WGIndex int64 `json:"-"`
}
User is a VPN client.
type UserStatus ¶
type UserStatus string
const ( UserActive UserStatus = "ACTIVE" UserDisabled UserStatus = "DISABLED" UserLimited UserStatus = "LIMITED" UserExpired UserStatus = "EXPIRED" )
func (UserStatus) Valid ¶
func (s UserStatus) Valid() bool