libtailscale, mdm: allow syspolicy to subscribe to policy change notifications (#462)

In preparation for upcoming syspolicy improvements, we'd like to allow subscriptions
to policy change notifications via the syspolicyHandler.RegisterChangeCallback.
The registered callbacks are invoked whenever MDMSettings.update is called.

Updates tailscale/tailscale#12687

Signed-off-by: Nick Khyl <nickk@tailscale.com>
pull/463/head
Nick Khyl 3 months ago committed by GitHub
parent 8767fbd8d8
commit 2a32ed1f30
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -338,6 +338,10 @@ class App : UninitializedApp(), libtailscale.AppContext {
throw MDMSettings.NoSuchKeyException()
}
}
fun notifyPolicyChanged() {
app.notifyPolicyChanged()
}
}
/**

@ -107,5 +107,6 @@ object MDMSettings {
val bundle = restrictionsManager?.applicationRestrictions
val preferences = lazy { app.getEncryptedPrefs() }
allSettings.forEach { it.setFrom(bundle, preferences) }
app.notifyPolicyChanged()
}
}

@ -45,6 +45,7 @@ type App struct {
appCtx AppContext
store *stateStore
policyStore *syspolicyHandler
logIDPublicAtomic atomic.Pointer[logid.PublicID]
localAPIHandler http.Handler

@ -102,6 +102,10 @@ type Application interface {
// it accepts multiple FileParts that get encoded as multipart/form-data.
CallLocalAPIMultipart(timeoutMillis int, method, endpoint string, parts FileParts) (LocalAPIResponse, error)
// NotifyPolicyChanged notifies the backend about a changed MDM policy,
// so it can re-read it via the [syspolicyHandler].
NotifyPolicyChanged()
// WatchNotifications provides a mechanism for subscribing to ipn.Notify
// updates. The given NotificationCallback's OnNotify function is invoked
// on every new ipn.Notify message. The returned NotificationManager

@ -107,6 +107,10 @@ func (app *App) CallLocalAPIMultipart(timeoutMillis int, method, endpoint string
}
}
func (app *App) NotifyPolicyChanged() {
app.policyStore.notifyChanged()
}
func (app *App) EditPrefs(prefs ipn.MaskedPrefs) (LocalAPIResponse, error) {
r, w := io.Pipe()
go func() {

@ -6,17 +6,21 @@ package libtailscale
import (
"encoding/json"
"errors"
"sync"
"tailscale.com/util/set"
"tailscale.com/util/syspolicy"
)
// syspolicyHandler is a syspolicy handler for the Android version of the Tailscale client,
// which lets the main networking code read values set via the Android RestrictionsManager.
type syspolicyHandler struct {
a *App
a *App
mu sync.RWMutex
cbs set.HandleSet[func()]
}
func (h syspolicyHandler) ReadString(key string) (string, error) {
func (h *syspolicyHandler) ReadString(key string) (string, error) {
if key == "" {
return "", syspolicy.ErrNoSuchKey
}
@ -24,7 +28,7 @@ func (h syspolicyHandler) ReadString(key string) (string, error) {
return retVal, translateHandlerError(err)
}
func (h syspolicyHandler) ReadBoolean(key string) (bool, error) {
func (h *syspolicyHandler) ReadBoolean(key string) (bool, error) {
if key == "" {
return false, syspolicy.ErrNoSuchKey
}
@ -32,7 +36,7 @@ func (h syspolicyHandler) ReadBoolean(key string) (bool, error) {
return retVal, translateHandlerError(err)
}
func (h syspolicyHandler) ReadUInt64(key string) (uint64, error) {
func (h *syspolicyHandler) ReadUInt64(key string) (uint64, error) {
if key == "" {
return 0, syspolicy.ErrNoSuchKey
}
@ -40,7 +44,7 @@ func (h syspolicyHandler) ReadUInt64(key string) (uint64, error) {
return 0, errors.New("ReadUInt64 is not implemented on Android")
}
func (h syspolicyHandler) ReadStringArray(key string) ([]string, error) {
func (h *syspolicyHandler) ReadStringArray(key string) ([]string, error) {
if key == "" {
return nil, syspolicy.ErrNoSuchKey
}
@ -59,6 +63,25 @@ func (h syspolicyHandler) ReadStringArray(key string) ([]string, error) {
return arr, err
}
func (h *syspolicyHandler) RegisterChangeCallback(cb func()) (unregister func(), err error) {
h.mu.Lock()
handle := h.cbs.Add(cb)
h.mu.Unlock()
return func() {
h.mu.Lock()
delete(h.cbs, handle)
h.mu.Unlock()
}, nil
}
func (h *syspolicyHandler) notifyChanged() {
h.mu.RLock()
for _, cb := range h.cbs {
go cb()
}
h.mu.RUnlock()
}
func translateHandlerError(err error) error {
if err != nil && !errors.Is(err, syspolicy.ErrNoSuchKey) && err.Error() == syspolicy.ErrNoSuchKey.Error() {
return syspolicy.ErrNoSuchKey

@ -39,8 +39,9 @@ func newApp(dataDir, directFileRoot string, appCtx AppContext) Application {
a.ready.Add(2)
a.store = newStateStore(a.appCtx)
a.policyStore = &syspolicyHandler{a: a}
netmon.RegisterInterfaceGetter(a.getInterfaces)
syspolicy.RegisterHandler(syspolicyHandler{a: a})
syspolicy.RegisterHandler(a.policyStore)
go func() {
defer func() {
if p := recover(); p != nil {

Loading…
Cancel
Save