autoAcceptIfLocked and more! (#7319)

stephannn committed Oct 28, 2025 at 18:20 UTC 49da5da9dd05d7cc1d8503f8c0a717e4ff2d2ef3
5 files changed +170 -17
agents/meshcore.js
+92 -16
@@ -1176,6 +1176,13 @@ function handleServerCommand(data) {
1176 tunnel.consentTimeout = (tunnel.soptions && tunnel.soptions.consentTimeout) ? tunnel.soptions.consentTimeout : 30;
1177 tunnel.consentAutoAccept = (tunnel.soptions && (tunnel.soptions.consentAutoAccept === true));
1178 tunnel.consentAutoAcceptIfNoUser = (tunnel.soptions && (tunnel.soptions.consentAutoAcceptIfNoUser === true));
1179 + tunnel.consentAutoAcceptIfDesktopNoUser = (tunnel.soptions && (tunnel.soptions.consentAutoAcceptIfDesktopNoUser === true));
1180 + tunnel.consentAutoAcceptIfTerminalNoUser = (tunnel.soptions && (tunnel.soptions.consentAutoAcceptIfTerminalNoUser === true));
1181 + tunnel.consentAutoAcceptIfFileNoUser = (tunnel.soptions && (tunnel.soptions.consentAutoAcceptIfFileNoUser === true));
1182 + tunnel.consentAutoAcceptIfLocked = (tunnel.soptions && (tunnel.soptions.consentAutoAcceptIfLocked === true));
1183 + tunnel.consentAutoAcceptIfDesktopLocked = (tunnel.soptions && (tunnel.soptions.consentAutoAcceptIfDesktopLocked === true));
1184 + tunnel.consentAutoAcceptIfTerminalLocked = (tunnel.soptions && (tunnel.soptions.consentAutoAcceptIfTerminalLocked === true));
1185 + tunnel.consentAutoAcceptIfFileLocked = (tunnel.soptions && (tunnel.soptions.consentAutoAcceptIfFileLocked === true));
1186 tunnel.oldStyle = (tunnel.soptions && tunnel.soptions.oldStyle) ? tunnel.soptions.oldStyle : false;
1187 tunnel.tcpaddr = data.tcpaddr;
1188 tunnel.tcpport = data.tcpport;
@@ -3067,7 +3074,7 @@ function onTunnelData(data)
3074 // Perform User-Consent if needed.
3075 if (this.httprequest.consent && (this.httprequest.consent & 16)) {
3076 // User asked for consent so now we check if we can auto accept if no user is present/loggedin
3070 - if (this.httprequest.consentAutoAcceptIfNoUser) {
3077 + if (this.httprequest.consentAutoAcceptIfNoUser || this.httprequest.consentAutoAcceptIfTerminalNoUser || this.httprequest.consentAutoAcceptIfLocked || this.httprequest.consentAutoAcceptIfTerminalLocked) {
3078 var p = require('user-sessions').enumerateUsers();
3079 p.sessionid = this.httprequest.sessionid;
3080 p.ws = this;
@@ -3076,10 +3083,35 @@ function onTunnelData(data)
3083 for (var i in u) {
3084 if (u[i].State == 'Active') { v.push({ tsid: i, type: u[i].StationName, user: u[i].Username, domain: u[i].Domain }); }
3085 }
3079 - if (v.length == 0) { // No user is present, auto accept
3086 + var autoAccept = false;
3087 +
3088 + // Check if we should auto-accept because no user is present
3089 + if ((this.ws.httprequest.consentAutoAcceptIfNoUser || this.ws.httprequest.consentAutoAcceptIfTerminalNoUser) && (v.length == 0)) {
3090 + autoAccept = true;
3091 + }
3092 +
3093 + // Check if we should auto-accept because all users are locked
3094 + if ((this.ws.httprequest.consentAutoAcceptIfLocked || this.ws.httprequest.consentAutoAcceptIfTerminalLocked) && (v.length > 0)) {
3095 + var allUsersLocked = true;
3096 + if (!meshCoreObj.lusers || meshCoreObj.lusers.length == 0) {
3097 + // No locked users list available, assume users are not locked
3098 + allUsersLocked = false;
3099 + } else {
3100 + for (var i in v) {
3101 + var username = v[i].domain ? (v[i].domain + '\\' + v[i].user) : v[i].user;
3102 + if (meshCoreObj.lusers.indexOf(username) == -1) {
3103 + allUsersLocked = false;
3104 + break;
3105 + }
3106 + }
3107 + }
3108 + if (allUsersLocked) { autoAccept = true; }
3109 + }
3110 +
3111 + if (autoAccept) {
3112 this.ws.httprequest.tpromise._res();
3113 } else {
3082 - // User is present so we still need consent
3114 + // User is present and not all locked, so we still need consent
3115 terminal_consent_ask(this.ws);
3116 }
3117 });
@@ -3188,7 +3220,7 @@ function onTunnelData(data)
3220 if (this.httprequest.consent && (this.httprequest.consent & 8)) {
3221
3222 // User asked for consent but now we check if can auto accept if no user is present
3191 - if (this.httprequest.consentAutoAcceptIfNoUser) {
3223 + if (this.httprequest.consentAutoAcceptIfNoUser || this.httprequest.consentAutoAcceptIfDesktopNoUser || this.httprequest.consentAutoAcceptIfLocked || this.httprequest.consentAutoAcceptIfDesktopLocked) {
3224 // Get list of users to check if we any actual users logged in, and if users logged in, we still need consent
3225 var p = require('user-sessions').enumerateUsers();
3226 p.sessionid = this.httprequest.sessionid;
@@ -3198,10 +3230,36 @@ function onTunnelData(data)
3230 for (var i in u) {
3231 if (u[i].State == 'Active') { v.push({ tsid: i, type: u[i].StationName, user: u[i].Username, domain: u[i].Domain }); }
3232 }
3201 - if (v.length == 0) { // No user is present, auto accept
3233 + var autoAccept = false;
3234 +
3235 + // Check if we can auto-accept because no user is present
3236 + if ((this.ws.httprequest.consentAutoAcceptIfNoUser || this.ws.httprequest.consentAutoAcceptIfDesktopNoUser) && (v.length == 0)) {
3237 + // No user is present, auto accept
3238 + autoAccept = true;
3239 + }
3240 +
3241 + // Check if we can auto-accept because all users are locked
3242 + if ((this.ws.httprequest.consentAutoAcceptIfLocked || this.ws.httprequest.consentAutoAcceptIfDesktopLocked) && (v.length > 0)) {
3243 + var allUsersLocked = true;
3244 + if (!meshCoreObj.lusers || meshCoreObj.lusers.length == 0) {
3245 + // No locked users list available, assume users are not locked
3246 + allUsersLocked = false;
3247 + } else {
3248 + for (var i in v) {
3249 + var username = v[i].domain ? (v[i].domain + '\\' + v[i].user) : v[i].user;
3250 + if (meshCoreObj.lusers.indexOf(username) == -1) {
3251 + allUsersLocked = false;
3252 + break;
3253 + }
3254 + }
3255 + }
3256 + if (allUsersLocked) { autoAccept = true; }
3257 + }
3258 +
3259 + if (autoAccept) {
3260 kvm_consent_ok(this.ws);
3261 } else {
3204 - // User is present so we still need consent
3262 + // User is present and not all locked, so we still need consent
3263 kvm_consent_ask(this.ws);
3264 }
3265 });
@@ -3259,10 +3317,7 @@ function onTunnelData(data)
3317 };
3318
3319 // Perform notification if needed. Toast messages may not be supported on all platforms.
3262 - if (this.httprequest.consent && (this.httprequest.consent & 32))
3263 - {
3264 - // User asked for consent so now we check if we can auto accept if no user is present/loggedin
3265 - if (this.httprequest.consentAutoAcceptIfNoUser) {
3320 + if (this.httprequest.consentAutoAcceptIfNoUser || this.httprequest.consentAutoAcceptIfFileNoUser || this.httprequest.consentAutoAcceptIfLocked || this.httprequest.consentAutoAcceptIfFileLocked) {
3321 var p = require('user-sessions').enumerateUsers();
3322 p.sessionid = this.httprequest.sessionid;
3323 p.ws = this;
@@ -3271,19 +3326,40 @@ function onTunnelData(data)
3326 for (var i in u) {
3327 if (u[i].State == 'Active') { v.push({ tsid: i, type: u[i].StationName, user: u[i].Username, domain: u[i].Domain }); }
3328 }
3274 - if (v.length == 0) { // No user is present, auto accept
3329 + var autoAccept = false;
3330 +
3331 + // Check if we should auto-accept because no user is present
3332 + if ((this.ws.httprequest.consentAutoAcceptIfNoUser || this.ws.httprequest.consentAutoAcceptIfFileNoUser) && (v.length == 0)) {
3333 + autoAccept = true;
3334 + }
3335 +
3336 + // Check if we should auto-accept because all users are locked
3337 + if ((this.ws.httprequest.consentAutoAcceptIfLocked || this.ws.httprequest.consentAutoAcceptIfFileLocked) && (v.length > 0)) {
3338 + var allUsersLocked = true;
3339 + if (!meshCoreObj.lusers || meshCoreObj.lusers.length == 0) {
3340 + // No locked users list available, assume users are not locked
3341 + allUsersLocked = false;
3342 + } else {
3343 + for (var i in v) {
3344 + var username = v[i].domain ? (v[i].domain + '\\' + v[i].user) : v[i].user;
3345 + if (meshCoreObj.lusers.indexOf(username) == -1) {
3346 + allUsersLocked = false;
3347 + break;
3348 + }
3349 + }
3350 + }
3351 + if (allUsersLocked) { autoAccept = true; }
3352 + }
3353 +
3354 + if (autoAccept) {
3355 // User Consent Prompt is not required
3356 files_consent_ok(this.ws);
3357 } else {
3278 - // User is present so we still need consent
3358 + // User is present and not all locked, so we still need consent
3359 files_consent_ask(this.ws);
3360 }
3361 });
3362 } else {
3283 - // User Consent Prompt is required
3284 - files_consent_ask(this);
3285 - }
3286 - } else {
3363 // User Consent Prompt is not required
3364 files_consent_ok(this);
3365 }
meshcentral-config-schema.json
+36 -1
@@ -2080,7 +2080,42 @@
2080 "autoAcceptIfNoUser": {
2081 "type": "boolean",
2082 "default": false,
2083 - "description": "If true, user consent is accepted if no user is logged in."
2083 + "description": "If true, user consents for desktop, terminal, and file are accepted if no user is logged in."
2084 + },
2085 + "autoAcceptIfDesktopNoUser": {
2086 + "type": "boolean",
2087 + "default": false,
2088 + "description": "If true, user consent for desktop access is accepted if no user is logged in."
2089 + },
2090 + "autoAcceptIfTerminalNoUser": {
2091 + "type": "boolean",
2092 + "default": false,
2093 + "description": "If true, user consent for terminal access is accepted if no user is logged in."
2094 + },
2095 + "autoAcceptIfFileNoUser": {
2096 + "type": "boolean",
2097 + "default": false,
2098 + "description": "If true, user consent for file access is accepted if no user is logged in."
2099 + },
2100 + "autoAcceptIfLocked": {
2101 + "type": "boolean",
2102 + "default": false,
2103 + "description": "If true, user consents for desktop, terminal, and file are accepted if device is locked."
2104 + },
2105 + "autoAcceptIfDesktopLocked": {
2106 + "type": "boolean",
2107 + "default": false,
2108 + "description": "If true, user consent for desktop access is accepted if device is locked."
2109 + },
2110 + "autoAcceptIfTerminalLocked": {
2111 + "type": "boolean",
2112 + "default": false,
2113 + "description": "If true, user consent for terminal access is accepted if device is locked."
2114 + },
2115 + "autoAcceptIfFileLocked": {
2116 + "type": "boolean",
2117 + "default": false,
2118 + "description": "If true, user consent for file access is accepted if device is locked."
2119 },
2120 "oldStyle": {
2121 "type": "boolean",
meshdesktopmultiplex.js
+7
@@ -1348,6 +1348,13 @@ function CreateMeshRelayEx2(parent, ws, req, domain, user, cookie) {
1348 if ((typeof domain.consentmessages.consenttimeout == 'number') && (domain.consentmessages.consenttimeout > 0)) { command.soptions.consentTimeout = domain.consentmessages.consenttimeout; }
1349 if (domain.consentmessages.autoacceptontimeout === true) { command.soptions.consentAutoAccept = true; }
1350 if (domain.consentmessages.autoacceptifnouser === true) { command.soptions.consentAutoAcceptIfNoUser = true; }
1351 + if (domain.consentmessages.autoacceptifdesktopnouser === true) { command.soptions.consentAutoAcceptIfDesktopNoUser = true; }
1352 + if (domain.consentmessages.autoacceptifterminalnouser === true) { command.soptions.consentAutoAcceptIfTerminalNoUser = true; }
1353 + if (domain.consentmessages.autoacceptiffilenouser === true) { command.soptions.consentAautoAcceptIfFileNoUser = true; }
1354 + if (domain.consentmessages.autoacceptiflocked === true) { command.soptions.consentAutoAcceptIfLocked = true; }
1355 + if (domain.consentmessages.autoacceptifdesktoplocked === true) { command.soptions.consentAutoAcceptIfDesktopLocked = true; }
1356 + if (domain.consentmessages.autoacceptifterminallocked === true) { command.soptions.consentAutoAcceptIfTerminalLocked = true; }
1357 + if (domain.consentmessages.autoacceptiffilelocked === true) { command.soptions.consentAutoAcceptIfFileLocked = true; }
1358 if (domain.consentmessages.oldstyle === true) { command.soptions.oldStyle = true; }
1359 }
1360 if (typeof domain.notificationmessages == 'object') {
meshrelay.js
+28
@@ -906,6 +906,13 @@ function CreateMeshRelayEx(parent, ws, req, domain, user, cookie) {
906 if ((typeof domain.consentmessages.consenttimeout == 'number') && (domain.consentmessages.consenttimeout > 0)) { command.soptions.consentTimeout = domain.consentmessages.consenttimeout; }
907 if (domain.consentmessages.autoacceptontimeout === true) { command.soptions.consentAutoAccept = true; }
908 if (domain.consentmessages.autoacceptifnouser === true) { command.soptions.consentAutoAcceptIfNoUser = true; }
909 + if (domain.consentmessages.autoacceptifdesktopnouser === true) { command.soptions.consentAutoAcceptIfDesktopNoUser = true; }
910 + if (domain.consentmessages.autoacceptifterminalnouser === true) { command.soptions.consentAutoAcceptIfTerminalNoUser = true; }
911 + if (domain.consentmessages.autoacceptiffilenouser === true) { command.soptions.consentAautoAcceptIfFileNoUser = true; }
912 + if (domain.consentmessages.autoacceptiflocked === true) { command.soptions.consentAutoAcceptIfLocked = true; }
913 + if (domain.consentmessages.autoacceptifdesktoplocked === true) { command.soptions.consentAutoAcceptIfDesktopLocked = true; }
914 + if (domain.consentmessages.autoacceptifterminallocked === true) { command.soptions.consentAutoAcceptIfTerminalLocked = true; }
915 + if (domain.consentmessages.autoacceptiffilelocked === true) { command.soptions.consentAutoAcceptIfFileLocked = true; }
916 if (domain.consentmessages.oldstyle === true) { command.soptions.oldStyle = true; }
917 }
918 if (typeof domain.notificationmessages == 'object') {
@@ -945,6 +952,13 @@ function CreateMeshRelayEx(parent, ws, req, domain, user, cookie) {
952 if ((typeof domain.consentmessages.consenttimeout == 'number') && (domain.consentmessages.consenttimeout > 0)) { command.soptions.consentTimeout = domain.consentmessages.consenttimeout; }
953 if (domain.consentmessages.autoacceptontimeout === true) { command.soptions.consentAutoAccept = true; }
954 if (domain.consentmessages.autoacceptifnouser === true) { command.soptions.consentAutoAcceptIfNoUser = true; }
955 + if (domain.consentmessages.autoacceptifdesktopnouser === true) { command.soptions.consentAutoAcceptIfDesktopNoUser = true; }
956 + if (domain.consentmessages.autoacceptifterminalnouser === true) { command.soptions.consentAutoAcceptIfTerminalNoUser = true; }
957 + if (domain.consentmessages.autoacceptiffilenouser === true) { command.soptions.consentAautoAcceptIfFileNoUser = true; }
958 + if (domain.consentmessages.autoacceptiflocked === true) { command.soptions.consentAutoAcceptIfLocked = true; }
959 + if (domain.consentmessages.autoacceptifdesktoplocked === true) { command.soptions.consentAutoAcceptIfDesktopLocked = true; }
960 + if (domain.consentmessages.autoacceptifterminallocked === true) { command.soptions.consentAutoAcceptIfTerminalLocked = true; }
961 + if (domain.consentmessages.autoacceptiffilelocked === true) { command.soptions.consentAutoAcceptIfFileLocked = true; }
962 if (domain.consentmessages.oldstyle === true) { command.soptions.oldStyle = true; }
963 }
964 if (typeof domain.notificationmessages == 'object') {
@@ -964,6 +978,13 @@ function CreateMeshRelayEx(parent, ws, req, domain, user, cookie) {
978 if ((typeof domain.consentmessages.consenttimeout == 'number') && (domain.consentmessages.consenttimeout > 0)) { command.soptions.consentTimeout = domain.consentmessages.consenttimeout; }
979 if (domain.consentmessages.autoacceptontimeout === true) { command.soptions.consentAutoAccept = true; }
980 if (domain.consentmessages.autoacceptifnouser === true) { command.soptions.consentAutoAcceptIfNoUser = true; }
981 + if (domain.consentmessages.autoacceptifdesktopnouser === true) { command.soptions.consentAutoAcceptIfDesktopNoUser = true; }
982 + if (domain.consentmessages.autoacceptifterminalnouser === true) { command.soptions.consentAutoAcceptIfTerminalNoUser = true; }
983 + if (domain.consentmessages.autoacceptiffilenouser === true) { command.soptions.consentAautoAcceptIfFileNoUser = true; }
984 + if (domain.consentmessages.autoacceptiflocked === true) { command.soptions.consentAutoAcceptIfLocked = true; }
985 + if (domain.consentmessages.autoacceptifdesktoplocked === true) { command.soptions.consentAutoAcceptIfDesktopLocked = true; }
986 + if (domain.consentmessages.autoacceptifterminallocked === true) { command.soptions.consentAutoAcceptIfTerminalLocked = true; }
987 + if (domain.consentmessages.autoacceptiffilelocked === true) { command.soptions.consentAutoAcceptIfFileLocked = true; }
988 if (domain.consentmessages.oldstyle === true) { command.soptions.oldStyle = true; }
989 }
990 if (typeof domain.notificationmessages == 'object') {
@@ -1017,6 +1038,13 @@ function CreateMeshRelayEx(parent, ws, req, domain, user, cookie) {
1038 if ((typeof domain.consentmessages.consenttimeout == 'number') && (domain.consentmessages.consenttimeout > 0)) { command.soptions.consentTimeout = domain.consentmessages.consenttimeout; }
1039 if (domain.consentmessages.autoacceptontimeout === true) { command.soptions.consentAutoAccept = true; }
1040 if (domain.consentmessages.autoacceptifnouser === true) { command.soptions.consentAutoAcceptIfNoUser = true; }
1041 + if (domain.consentmessages.autoacceptifdesktopnouser === true) { command.soptions.consentAutoAcceptIfDesktopNoUser = true; }
1042 + if (domain.consentmessages.autoacceptifterminalnouser === true) { command.soptions.consentAutoAcceptIfTerminalNoUser = true; }
1043 + if (domain.consentmessages.autoacceptiffilenouser === true) { command.soptions.consentAautoAcceptIfFileNoUser = true; }
1044 + if (domain.consentmessages.autoacceptiflocked === true) { command.soptions.consentAutoAcceptIfLocked = true; }
1045 + if (domain.consentmessages.autoacceptifdesktoplocked === true) { command.soptions.consentAutoAcceptIfDesktopLocked = true; }
1046 + if (domain.consentmessages.autoacceptifterminallocked === true) { command.soptions.consentAutoAcceptIfTerminalLocked = true; }
1047 + if (domain.consentmessages.autoacceptiffilelocked === true) { command.soptions.consentAutoAcceptIfFileLocked = true; }
1048 if (domain.consentmessages.oldstyle === true) { command.soptions.oldStyle = true; }
1049 }
1050 if (typeof domain.notificationmessages == 'object') {
meshuser.js
+7
@@ -1009,6 +1009,13 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
1009 if ((typeof domain.consentmessages.consenttimeout == 'number') && (domain.consentmessages.consenttimeout > 0)) { command.soptions.consentTimeout = domain.consentmessages.consenttimeout; }
1010 if (domain.consentmessages.autoacceptontimeout === true) { command.soptions.consentAutoAccept = true; }
1011 if (domain.consentmessages.autoacceptifnouser === true) { command.soptions.consentAutoAcceptIfNoUser = true; }
1012 + if (domain.consentmessages.autoacceptifdesktopnouser === true) { command.soptions.consentAutoAcceptIfDesktopNoUser = true; }
1013 + if (domain.consentmessages.autoacceptifterminalnouser === true) { command.soptions.consentAutoAcceptIfTerminalNoUser = true; }
1014 + if (domain.consentmessages.autoacceptiffilenouser === true) { command.soptions.consentAautoAcceptIfFileNoUser = true; }
1015 + if (domain.consentmessages.autoacceptiflocked === true) { command.soptions.consentAutoAcceptIfLocked = true; }
1016 + if (domain.consentmessages.autoacceptifdesktoplocked === true) { command.soptions.consentAutoAcceptIfDesktopLocked = true; }
1017 + if (domain.consentmessages.autoacceptifterminallocked === true) { command.soptions.consentAutoAcceptIfTerminalLocked = true; }
1018 + if (domain.consentmessages.autoacceptiffilelocked === true) { command.soptions.consentAutoAcceptIfFileLocked = true; }
1019 if (domain.consentmessages.oldstyle === true) { command.soptions.oldStyle = true; }
1020 }
1021 if (typeof domain.notificationmessages == 'object') {