mirror of
https://github.com/screentinker/screentinker.git
synced 2026-08-13 13:53:12 -06:00
A player stands down from self-updating when another device owner manages the panel, on the assumption that the MDM distributes packages instead. That assumption does not always hold: an operator may run an MDM for policy alone and still want ScreenTinker's OTA to own the player. Until now there was no way to say so — the stand-down was a client-side decision with no operator input. OTA_ALLOW_MANAGED_DEVICES=1 makes the server advertise `allow_managed: true` in /api/update/check, and players skip the stand-down. Default off: the safe behaviour stays the default, and only an explicit opt-in changes it. Absence is not consent. The client parses the field with a false default, so a newer player against an older server that has never heard of it still stands down; and the server always emits the key, so a player can tell "the operator said no" from "this server has no opinion". Config parsing is strict for the same reason — only 1/true enable it, and anything else, including a plausible typo like "ture" or "yes", lands on the safe side rather than riding JavaScript truthiness. This deliberately does NOT grant silent install. Off device-owner, and without DELEGATION_PACKAGE_INSTALLATION delegated by the MDM, Android still raises a confirm dialog somebody has to accept, so the override alone will not fix a fleet whose installs are failing at that dialog — delegating the scope is the real fix there. The README says so at the point of use, because reaching for this flag is the natural mistake. Only reachable because the stand-down now runs after the version check rather than before it; it needs the server's answer in hand to consult.
53 lines
2.3 KiB
JavaScript
53 lines
2.3 KiB
JavaScript
'use strict';
|
|
|
|
// #166 escape hatch: OTA_ALLOW_MANAGED_DEVICES lets players self-update even when an MDM/DPC owns
|
|
// the device. The default has to be OFF, and "off" has to be the answer for every shape of a
|
|
// not-set / mistyped value — an operator who fat-fingers the variable must not silently get the
|
|
// unsafe behaviour, because the failure mode is an install confirm dialog parked over a customer's
|
|
// content on a fleet nobody is standing in front of.
|
|
//
|
|
// The value is also advertised to players as `allow_managed` in /api/update/check. A player that
|
|
// gets no field at all (older server) must read that as NO. Absence is not consent.
|
|
|
|
const { test } = require('node:test');
|
|
const assert = require('node:assert/strict');
|
|
|
|
function loadConfig(value) {
|
|
if (value === undefined) delete process.env.OTA_ALLOW_MANAGED_DEVICES;
|
|
else process.env.OTA_ALLOW_MANAGED_DEVICES = value;
|
|
delete require.cache[require.resolve('../config')];
|
|
return require('../config');
|
|
}
|
|
|
|
test('THE DEFAULT: unset means managed devices do NOT self-update', () => {
|
|
const config = loadConfig(undefined);
|
|
assert.equal(config.otaAllowManagedDevices, false);
|
|
assert.equal(typeof config.otaAllowManagedDevices, 'boolean');
|
|
});
|
|
|
|
test('the documented ways to turn it on', () => {
|
|
for (const v of ['1', 'true', 'TRUE', 'True']) {
|
|
assert.equal(loadConfig(v).otaAllowManagedDevices, true, `${v} should enable`);
|
|
}
|
|
});
|
|
|
|
test('everything else is OFF — a typo must not enable an unsafe default', () => {
|
|
// '0'/'false' are the explicit no. The rest are the fat-finger cases: they must land on the
|
|
// safe side rather than being treated as "any non-empty string is truthy".
|
|
for (const v of ['0', 'false', 'FALSE', 'no', 'off', 'yes', 'ture', 'enabled', '2', '', ' ']) {
|
|
assert.equal(loadConfig(v).otaAllowManagedDevices, false, `${JSON.stringify(v)} should stay off`);
|
|
}
|
|
});
|
|
|
|
test('it is always a real boolean, never a string, so the JSON field is unambiguous', () => {
|
|
// Players read this over the wire; the string "false" is truthy in every client language.
|
|
for (const v of [undefined, '1', 'nonsense']) {
|
|
assert.equal(typeof loadConfig(v).otaAllowManagedDevices, 'boolean');
|
|
}
|
|
});
|
|
|
|
test.after(() => {
|
|
delete process.env.OTA_ALLOW_MANAGED_DEVICES;
|
|
delete require.cache[require.resolve('../config')];
|
|
});
|