mirror of
https://github.com/AdguardTeam/AdGuardDNS.git
synced 2025-02-20 11:23:36 +08:00
130 lines
3.7 KiB
Go
130 lines
3.7 KiB
Go
package agd
|
|
|
|
import (
|
|
"fmt"
|
|
"net/netip"
|
|
"unicode/utf8"
|
|
|
|
"github.com/AdguardTeam/AdGuardDNS/internal/agdpasswd"
|
|
"github.com/AdguardTeam/golibs/errors"
|
|
"github.com/AdguardTeam/golibs/netutil"
|
|
)
|
|
|
|
// Device is a device of a device attached to a profile.
|
|
//
|
|
// NOTE: Do not change fields of this structure without incrementing
|
|
// [internal/profiledb/internal.FileCacheVersion].
|
|
type Device struct {
|
|
// Auth defines authentication settings of this device. It's never nil.
|
|
Auth *AuthSettings
|
|
|
|
// ID is the unique ID of the device.
|
|
ID DeviceID
|
|
|
|
// LinkedIP, when non-empty, allows AdGuard DNS to identify a device by its
|
|
// IP address when it can only use plain DNS.
|
|
LinkedIP netip.Addr
|
|
|
|
// Name is the human-readable name of the device.
|
|
Name DeviceName
|
|
|
|
// HumanIDLower is the lower-case version of the normalized [HumanID] used
|
|
// to create this device, if any.
|
|
HumanIDLower HumanIDLower
|
|
|
|
// DedicatedIPs are the destination (server) IP-addresses dedicated to this
|
|
// device, if any. A device can use one of these addresses as a DNS server
|
|
// address for AdGuard DNS to recognize it.
|
|
DedicatedIPs []netip.Addr
|
|
|
|
// FilteringEnabled defines whether queries from the device should be
|
|
// filtered in any way at all.
|
|
FilteringEnabled bool
|
|
}
|
|
|
|
// DeviceID is the ID of a device attached to a profile. It is an opaque
|
|
// string.
|
|
type DeviceID string
|
|
|
|
// The maximum and minimum lengths of a device ID.
|
|
const (
|
|
MaxDeviceIDLen = 8
|
|
MinDeviceIDLen = 1
|
|
)
|
|
|
|
// NewDeviceID converts a simple string into a DeviceID and makes sure that it's
|
|
// valid. This should be preferred to a simple type conversion.
|
|
func NewDeviceID(s string) (id DeviceID, err error) {
|
|
// Do not use errors.Annotate here, because it allocates even when the error
|
|
// is nil.
|
|
//
|
|
// TODO(a.garipov): Find out, why does it allocate and perhaps file an
|
|
// issue about that in the Go issue tracker.
|
|
defer func() {
|
|
if err != nil {
|
|
err = fmt.Errorf("bad device id %q: %w", s, err)
|
|
}
|
|
}()
|
|
|
|
err = ValidateInclusion(len(s), MaxDeviceIDLen, MinDeviceIDLen, UnitByte)
|
|
if err != nil {
|
|
// The error will be wrapped by the deferred helper.
|
|
return "", err
|
|
}
|
|
|
|
err = netutil.ValidateHostnameLabel(s)
|
|
if err != nil {
|
|
// Unwrap the error to replace the domain name label wrapper message
|
|
// with our own.
|
|
return "", errors.Unwrap(err)
|
|
}
|
|
|
|
return DeviceID(s), nil
|
|
}
|
|
|
|
// DeviceName is the human-readable name of a device attached to a profile.
|
|
type DeviceName string
|
|
|
|
// MaxDeviceNameRuneLen is the maximum length of a human-readable device name in
|
|
// runes.
|
|
const MaxDeviceNameRuneLen = 128
|
|
|
|
// NewDeviceName converts a simple string into a DeviceName and makes sure that
|
|
// it's valid. This should be preferred to a simple type conversion.
|
|
func NewDeviceName(s string) (n DeviceName, err error) {
|
|
// Do not use errors.Annotate here, because it allocates even when the error
|
|
// is nil.
|
|
//
|
|
// TODO(a.garipov): Same as the TODO in NewDeviceID.
|
|
defer func() {
|
|
if err != nil {
|
|
err = fmt.Errorf("bad device name %q: %w", s, err)
|
|
}
|
|
}()
|
|
|
|
err = ValidateInclusion(utf8.RuneCountInString(s), MaxDeviceNameRuneLen, 0, UnitRune)
|
|
if err != nil {
|
|
// The error will be wrapped by the deferred helper.
|
|
return "", err
|
|
}
|
|
|
|
return DeviceName(s), nil
|
|
}
|
|
|
|
// AuthSettings are the authentication settings of a device.
|
|
//
|
|
// NOTE: Do not change fields of this structure without incrementing
|
|
// [internal/profiledb/internal.FileCacheVersion].
|
|
type AuthSettings struct {
|
|
// PasswordHash is the hash of the auth password. It is never nil.
|
|
PasswordHash agdpasswd.Authenticator
|
|
|
|
// Enabled tells whether the authentication should be enabled at all.
|
|
// This must be true in order for all parameters to work.
|
|
Enabled bool
|
|
|
|
// DoHAuthOnly defines if the device should only be authenticated through
|
|
// DoH protocol.
|
|
DoHAuthOnly bool
|
|
}
|