autoAcceptIfNoUser (#6759)
* autoAcceptIfNoUser for desktop * autoAcceptIfNoUser for terminal * autoAcceptIfNoUser for files * forgot few extra files --------- Signed-off-by: si458 <simonsmith5521@gmail.com>
Simon Smith committed
Feb 9, 2025 at 19:54 UTC
711bb56a93d27a04a4c102c8a9c8a56ff415fbc9
6 files changed
+290
-240
agents/meshcore.js
+278
-240
@@ -1158,6 +1158,7 @@ function handleServerCommand(data) {
1158
tunnel.soptions = data.soptions;
1159
tunnel.consentTimeout = (tunnel.soptions && tunnel.soptions.consentTimeout) ? tunnel.soptions.consentTimeout : 30;
1160
tunnel.consentAutoAccept = (tunnel.soptions && (tunnel.soptions.consentAutoAccept === true));
1161
+ tunnel.consentAutoAcceptIfNoUser = (tunnel.soptions && (tunnel.soptions.consentAutoAcceptIfNoUser === true));
1162
tunnel.oldStyle = (tunnel.soptions && tunnel.soptions.oldStyle) ? tunnel.soptions.oldStyle : false;
1163
tunnel.tcpaddr = data.tcpaddr;
1164
tunnel.tcpport = data.tcpport;
@@ -2297,6 +2298,58 @@ function terminal_end()
2298
2299
}
2300
2301
+function terminal_consent_ask(ws) {
2302
+ ws.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: "Waiting for user to grant access...", msgid: 1 }));
2303
+ var consentMessage = currentTranslation['terminalConsent'].replace('{0}', ws.httprequest.realname).replace('{1}', ws.httprequest.username);
2304
+ var consentTitle = 'MeshCentral';
2305
+ if (ws.httprequest.soptions != null) {
2306
+ if (ws.httprequest.soptions.consentTitle != null) { consentTitle = ws.httprequest.soptions.consentTitle; }
2307
+ if (ws.httprequest.soptions.consentMsgTerminal != null) { consentMessage = ws.httprequest.soptions.consentMsgTerminal.replace('{0}', ws.httprequest.realname).replace('{1}', ws.httprequest.username); }
2308
+ }
2309
+ if (process.platform == 'win32') {
2310
+ var enhanced = false;
2311
+ if (ws.httprequest.oldStyle === false) {
2312
+ try { require('win-userconsent'); enhanced = true; } catch (ex) { }
2313
+ }
2314
+ if (enhanced) {
2315
+ var ipr = server_getUserImage(ws.httprequest.userid);
2316
+ ipr.consentTitle = consentTitle;
2317
+ ipr.consentMessage = consentMessage;
2318
+ ipr.consentTimeout = ws.httprequest.consentTimeout;
2319
+ ipr.consentAutoAccept = ws.httprequest.consentAutoAccept;
2320
+ ipr.username = ws.httprequest.realname;
2321
+ ipr.translations = { Allow: currentTranslation['allow'], Deny: currentTranslation['deny'], Auto: currentTranslation['autoAllowForFive'], Caption: consentMessage };
2322
+ ws.httprequest.tpromise._consent = ipr.then(function (img) {
2323
+ this.consent = require('win-userconsent').create(this.consentTitle, this.consentMessage, this.username, { b64Image: img.split(',').pop(), timeout: this.consentTimeout * 1000, timeoutAutoAccept: this.consentAutoAccept, translations: this.translations, background: color_options.background, foreground: color_options.foreground });
2324
+ this.__childPromise.close = this.consent.close.bind(this.consent);
2325
+ return (this.consent);
2326
+ });
2327
+ } else {
2328
+ ws.httprequest.tpromise._consent = require('message-box').create(consentTitle, consentMessage, ws.httprequest.consentTimeout);
2329
+ }
2330
+ } else {
2331
+ ws.httprequest.tpromise._consent = require('message-box').create(consentTitle, consentMessage, ws.httprequest.consentTimeout);
2332
+ }
2333
+ ws.httprequest.tpromise._consent.retPromise = ws.httprequest.tpromise;
2334
+ ws.httprequest.tpromise._consent.then(function (always) {
2335
+ if (always && process.platform == 'win32') { server_set_consentTimer(this.retPromise.httprequest.userid); }
2336
+ // Success
2337
+ MeshServerLogEx(27, null, "Local user accepted remote terminal request (" + this.retPromise.httprequest.remoteaddr + ")", this.retPromise.that.httprequest);
2338
+ this.retPromise.that.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: null, msgid: 0 }));
2339
+ this.retPromise._consent = null;
2340
+ this.retPromise._res();
2341
+ }, function (e) {
2342
+ if (this.retPromise.that) {
2343
+ if(this.retPromise.that.httprequest){ // User Consent Denied
2344
+ MeshServerLogEx(28, null, "Local user rejected remote terminal request (" + this.retPromise.that.httprequest.remoteaddr + ")", this.retPromise.that.httprequest);
2345
+ } else { } // Connection was closed server side, maybe log some messages somewhere?
2346
+ this.retPromise._consent = null;
2347
+ this.retPromise.that.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: e.toString(), msgid: 2 }));
2348
+ } else { } // no websocket, maybe log some messages somewhere?
2349
+ this.retPromise._rej(e.toString());
2350
+ });
2351
+}
2352
+
2353
function terminal_promise_connection_rejected(e)
2354
{
2355
// FAILED to connect terminal
@@ -2609,6 +2662,101 @@ function kvm_tunnel_consentpromise_closehandler()
2662
if (this._consentpromise && this._consentpromise.close) { this._consentpromise.close(); }
2663
}
2664
2665
+function kvm_consent_ok(ws) {
2666
+ // User Consent Prompt is not required because no user is present
2667
+ if (ws.httprequest.consent && (ws.httprequest.consent & 1)){
2668
+ // User Notifications is required
2669
+ MeshServerLogEx(35, null, "Started remote desktop with toast notification (" + ws.httprequest.remoteaddr + ")", ws.httprequest);
2670
+ var notifyMessage = currentTranslation['desktopNotify'].replace('{0}', ws.httprequest.realname);
2671
+ var notifyTitle = "MeshCentral";
2672
+ if (ws.httprequest.soptions != null) {
2673
+ if (ws.httprequest.soptions.notifyTitle != null) { notifyTitle = ws.httprequest.soptions.notifyTitle; }
2674
+ if (ws.httprequest.soptions.notifyMsgDesktop != null) { notifyMessage = ws.httprequest.soptions.notifyMsgDesktop.replace('{0}', ws.httprequest.realname).replace('{1}', ws.httprequest.username); }
2675
+ }
2676
+ try { require('toaster').Toast(notifyTitle, notifyMessage, ws.tsid); } catch (ex) { }
2677
+ } else {
2678
+ MeshServerLogEx(36, null, "Started remote desktop without notification (" + ws.httprequest.remoteaddr + ")", ws.httprequest);
2679
+ }
2680
+ if (ws.httprequest.consent && (ws.httprequest.consent & 0x40)) {
2681
+ // Connection Bar is required
2682
+ if (ws.httprequest.desktop.kvm.connectionBar) {
2683
+ ws.httprequest.desktop.kvm.connectionBar.removeAllListeners('close');
2684
+ ws.httprequest.desktop.kvm.connectionBar.close();
2685
+ }
2686
+ try {
2687
+ ws.httprequest.desktop.kvm.connectionBar = require('notifybar-desktop')(ws.httprequest.privacybartext.replace('{0}', ws.httprequest.desktop.kvm.rusers.join(', ')).replace('{1}', ws.httprequest.desktop.kvm.users.join(', ')).replace(/'/g, "\\'\\"), require('MeshAgent')._tsid, color_options);
2688
+ MeshServerLogEx(31, null, "Remote Desktop Connection Bar Activated/Updated (" + ws.httprequest.remoteaddr + ")", ws.httprequest);
2689
+ } catch (ex) {
2690
+ MeshServerLogEx(32, null, "Remote Desktop Connection Bar Failed or not Supported (" + ws.httprequest.remoteaddr + ")", ws.httprequest);
2691
+ }
2692
+ if (ws.httprequest.desktop.kvm.connectionBar) {
2693
+ ws.httprequest.desktop.kvm.connectionBar.state = {
2694
+ userid: ws.httprequest.userid,
2695
+ xuserid: ws.httprequest.xuserid,
2696
+ username: ws.httprequest.username,
2697
+ sessionid: ws.httprequest.sessionid,
2698
+ remoteaddr: ws.httprequest.remoteaddr,
2699
+ guestname: ws.httprequest.guestname,
2700
+ desktop: ws.httprequest.desktop
2701
+ };
2702
+ ws.httprequest.desktop.kvm.connectionBar.on('close', function () {
2703
+ console.info1('Connection Bar Forcefully closed');
2704
+ MeshServerLogEx(29, null, "Remote Desktop Connection forcefully closed by local user (" + this.state.remoteaddr + ")", this.state);
2705
+ for (var i in this.state.desktop.kvm._pipedStreams) {
2706
+ this.state.desktop.kvm._pipedStreams[i].end();
2707
+ }
2708
+ this.state.desktop.kvm.end();
2709
+ });
2710
+ }
2711
+ }
2712
+ ws.httprequest.desktop.kvm.pipe(ws, { dataTypeSkip: 1 });
2713
+ if (ws.httprequest.autolock) {
2714
+ destopLockHelper_pipe(ws.httprequest);
2715
+ }
2716
+}
2717
+
2718
+function kvm_consent_ask(ws){
2719
+ // Send a console message back using the console channel, "\n" is supported.
2720
+ ws.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: "Waiting for user to grant access...", msgid: 1 }));
2721
+ var consentMessage = currentTranslation['desktopConsent'].replace('{0}', ws.httprequest.realname).replace('{1}', ws.httprequest.username);
2722
+ var consentTitle = 'MeshCentral';
2723
+ if (ws.httprequest.soptions != null) {
2724
+ if (ws.httprequest.soptions.consentTitle != null) { consentTitle = ws.httprequest.soptions.consentTitle; }
2725
+ if (ws.httprequest.soptions.consentMsgDesktop != null) { consentMessage = ws.httprequest.soptions.consentMsgDesktop.replace('{0}', ws.httprequest.realname).replace('{1}', ws.httprequest.username); }
2726
+ }
2727
+ var pr;
2728
+ if (process.platform == 'win32') {
2729
+ var enhanced = false;
2730
+ if (ws.httprequest.oldStyle === false) {
2731
+ try { require('win-userconsent'); enhanced = true; } catch (ex) { }
2732
+ }
2733
+ if (enhanced) {
2734
+ var ipr = server_getUserImage(ws.httprequest.userid);
2735
+ ipr.consentTitle = consentTitle;
2736
+ ipr.consentMessage = consentMessage;
2737
+ ipr.consentTimeout = ws.httprequest.consentTimeout;
2738
+ ipr.consentAutoAccept = ws.httprequest.consentAutoAccept;
2739
+ ipr.tsid = this.tsid;
2740
+ ipr.username = ws.httprequest.realname;
2741
+ ipr.translation = { Allow: currentTranslation['allow'], Deny: currentTranslation['deny'], Auto: currentTranslation['autoAllowForFive'], Caption: consentMessage };
2742
+ pr = ipr.then(function (img) {
2743
+ this.consent = require('win-userconsent').create(this.consentTitle, this.consentMessage, this.username, { b64Image: img.split(',').pop(), uid: this.tsid, timeout: this.consentTimeout * 1000, timeoutAutoAccept: this.consentAutoAccept, translations: this.translation, background: color_options.background, foreground: color_options.foreground });
2744
+ this.__childPromise.close = this.consent.close.bind(this.consent);
2745
+ return (this.consent);
2746
+ });
2747
+ } else {
2748
+ pr = require('message-box').create(consentTitle, consentMessage, ws.httprequest.consentTimeout, null, this.tsid);
2749
+ }
2750
+ } else {
2751
+ pr = require('message-box').create(consentTitle, consentMessage, ws.httprequest.consentTimeout, null, this.tsid);
2752
+ }
2753
+ pr.ws = ws;
2754
+ ws.pause();
2755
+ ws._consentpromise = pr;
2756
+ ws.prependOnceListener('end', kvm_tunnel_consentpromise_closehandler);
2757
+ pr.then(kvm_consentpromise_resolved, kvm_consentpromise_rejected);
2758
+}
2759
+
2760
function kvm_consentpromise_rejected(e)
2761
{
2762
if (this.ws) {
@@ -2688,6 +2836,66 @@ function kvm_consentpromise_resolved(always)
2836
this.ws = null;
2837
}
2838
2839
+function files_consent_ok(ws){
2840
+ // User Consent Prompt is not required
2841
+ if (ws.httprequest.consent && (ws.httprequest.consent & 4)) {
2842
+ // User Notifications is required
2843
+ MeshServerLogEx(42, null, "Started remote files with toast notification (" + ws.httprequest.remoteaddr + ")", ws.httprequest);
2844
+ var notifyMessage = currentTranslation['fileNotify'].replace('{0}', ws.httprequest.realname);
2845
+ var notifyTitle = "MeshCentral";
2846
+ if (ws.httprequest.soptions != null) {
2847
+ if (ws.httprequest.soptions.notifyTitle != null) { notifyTitle = ws.httprequest.soptions.notifyTitle; }
2848
+ if (ws.httprequest.soptions.notifyMsgFiles != null) { notifyMessage = ws.httprequest.soptions.notifyMsgFiles.replace('{0}', ws.httprequest.realname).replace('{1}', ws.httprequest.username); }
2849
+ }
2850
+ try { require('toaster').Toast(notifyTitle, notifyMessage); } catch (ex) { }
2851
+ } else {
2852
+ MeshServerLogEx(43, null, "Started remote files without notification (" + ws.httprequest.remoteaddr + ")", ws.httprequest);
2853
+ }
2854
+ ws.resume();
2855
+}
2856
+
2857
+function files_consent_ask(ws){
2858
+ // Send a console message back using the console channel, "\n" is supported.
2859
+ ws.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: "Waiting for user to grant access...", msgid: 1 }));
2860
+ var consentMessage = currentTranslation['fileConsent'].replace('{0}', ws.httprequest.realname).replace('{1}', ws.httprequest.username);
2861
+ var consentTitle = 'MeshCentral';
2862
+
2863
+ if (ws.httprequest.soptions != null) {
2864
+ if (ws.httprequest.soptions.consentTitle != null) { consentTitle = ws.httprequest.soptions.consentTitle; }
2865
+ if (ws.httprequest.soptions.consentMsgFiles != null) { consentMessage = ws.httprequest.soptions.consentMsgFiles.replace('{0}', ws.httprequest.realname).replace('{1}', ws.httprequest.username); }
2866
+ }
2867
+ var pr;
2868
+ if (process.platform == 'win32') {
2869
+ var enhanced = false;
2870
+ if (ws.httprequest.oldStyle === false) {
2871
+ try { require('win-userconsent'); enhanced = true; } catch (ex) { }
2872
+ }
2873
+ if (enhanced) {
2874
+ var ipr = server_getUserImage(ws.httprequest.userid);
2875
+ ipr.consentTitle = consentTitle;
2876
+ ipr.consentMessage = consentMessage;
2877
+ ipr.consentTimeout = ws.httprequest.consentTimeout;
2878
+ ipr.consentAutoAccept = ws.httprequest.consentAutoAccept;
2879
+ ipr.username = ws.httprequest.realname;
2880
+ ipr.translations = { Allow: currentTranslation['allow'], Deny: currentTranslation['deny'], Auto: currentTranslation['autoAllowForFive'], Caption: consentMessage };
2881
+ pr = ipr.then(function (img) {
2882
+ this.consent = require('win-userconsent').create(this.consentTitle, this.consentMessage, this.username, { b64Image: img.split(',').pop(), timeout: this.consentTimeout * 1000, timeoutAutoAccept: this.consentAutoAccept, translations: this.translations, background: color_options.background, foreground: color_options.foreground });
2883
+ this.__childPromise.close = this.consent.close.bind(this.consent);
2884
+ return (this.consent);
2885
+ });
2886
+ } else {
2887
+ pr = require('message-box').create(consentTitle, consentMessage, ws.httprequest.consentTimeout, null);
2888
+ }
2889
+ } else {
2890
+ pr = require('message-box').create(consentTitle, consentMessage, ws.httprequest.consentTimeout, null);
2891
+ }
2892
+ pr.ws = ws;
2893
+ ws.pause();
2894
+ ws._consentpromise = pr;
2895
+ ws.prependOnceListener('end', files_tunnel_endhandler);
2896
+ pr.then(files_consentpromise_resolved, files_consentpromise_rejected);
2897
+}
2898
+
2899
function files_consentpromise_resolved(always)
2900
{
2901
if (always && process.platform == 'win32') { server_set_consentTimer(this.ws.httprequest.userid); }
@@ -2817,76 +3025,31 @@ function onTunnelData(data)
3025
this.end = terminal_end;
3026
3027
// Perform User-Consent if needed.
2820
- if (this.httprequest.consent && (this.httprequest.consent & 16))
2821
- {
2822
- this.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: "Waiting for user to grant access...", msgid: 1 }));
2823
- var consentMessage = currentTranslation['terminalConsent'].replace('{0}', this.httprequest.realname).replace('{1}', this.httprequest.username);
2824
- var consentTitle = 'MeshCentral';
2825
-
2826
- if (this.httprequest.soptions != null)
2827
- {
2828
- if (this.httprequest.soptions.consentTitle != null) { consentTitle = this.httprequest.soptions.consentTitle; }
2829
- if (this.httprequest.soptions.consentMsgTerminal != null) { consentMessage = this.httprequest.soptions.consentMsgTerminal.replace('{0}', this.httprequest.realname).replace('{1}', this.httprequest.username); }
2830
- }
2831
- if (process.platform == 'win32')
2832
- {
2833
- var enhanced = false;
2834
- if (this.httprequest.oldStyle === false) {
2835
- try { require('win-userconsent'); enhanced = true; } catch (ex) { }
2836
- }
2837
- if (enhanced)
2838
- {
2839
- var ipr = server_getUserImage(this.httprequest.userid);
2840
- ipr.consentTitle = consentTitle;
2841
- ipr.consentMessage = consentMessage;
2842
- ipr.consentTimeout = this.httprequest.consentTimeout;
2843
- ipr.consentAutoAccept = this.httprequest.consentAutoAccept;
2844
- ipr.username = this.httprequest.realname;
2845
- ipr.translations = { Allow: currentTranslation['allow'], Deny: currentTranslation['deny'], Auto: currentTranslation['autoAllowForFive'], Caption: consentMessage };
2846
- this.httprequest.tpromise._consent = ipr.then(function (img)
2847
- {
2848
- this.consent = require('win-userconsent').create(this.consentTitle, this.consentMessage, this.username, { b64Image: img.split(',').pop(), timeout: this.consentTimeout * 1000, timeoutAutoAccept: this.consentAutoAccept, translations: this.translations, background: color_options.background, foreground: color_options.foreground });
2849
- this.__childPromise.close = this.consent.close.bind(this.consent);
2850
- return (this.consent);
2851
- });
2852
- } else
2853
- {
2854
- this.httprequest.tpromise._consent = require('message-box').create(consentTitle, consentMessage, this.httprequest.consentTimeout);
2855
- }
2856
- } else
2857
- {
2858
- this.httprequest.tpromise._consent = require('message-box').create(consentTitle, consentMessage, this.httprequest.consentTimeout);
2859
- }
2860
- this.httprequest.tpromise._consent.retPromise = this.httprequest.tpromise;
2861
- this.httprequest.tpromise._consent.then(
2862
- function (always)
2863
- {
2864
- if (always && process.platform == 'win32') { server_set_consentTimer(this.retPromise.httprequest.userid); }
2865
-
2866
- // Success
2867
- MeshServerLogEx(27, null, "Local user accepted remote terminal request (" + this.retPromise.httprequest.remoteaddr + ")", this.retPromise.that.httprequest);
2868
- this.retPromise.that.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: null, msgid: 0 }));
2869
- this.retPromise._consent = null;
2870
- this.retPromise._res();
2871
- },
2872
- function (e) {
2873
- if (this.retPromise.that) {
2874
- if(this.retPromise.that.httprequest){ // User Consent Denied
2875
- MeshServerLogEx(28, null, "Local user rejected remote terminal request (" + this.retPromise.that.httprequest.remoteaddr + ")", this.retPromise.that.httprequest);
2876
- } else { } // Connection was closed server side, maybe log some messages somewhere?
2877
- this.retPromise._consent = null;
2878
- this.retPromise.that.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: e.toString(), msgid: 2 }));
2879
- } else { } // no websocket, maybe log some messages somewhere?
2880
- this.retPromise._rej(e.toString());
3028
+ if (this.httprequest.consent && (this.httprequest.consent & 16)) {
3029
+ // User asked for consent so now we check if we can auto accept if no user is present/loggedin
3030
+ if (this.httprequest.consentAutoAcceptIfNoUser) {
3031
+ var p = require('user-sessions').enumerateUsers();
3032
+ p.sessionid = this.httprequest.sessionid;
3033
+ p.ws = this;
3034
+ p.then(function (u) {
3035
+ var v = [];
3036
+ for (var i in u) {
3037
+ if (u[i].State == 'Active') { v.push({ tsid: i, type: u[i].StationName, user: u[i].Username, domain: u[i].Domain }); }
3038
+ }
3039
+ if (v.length == 0) { // No user is present, auto accept
3040
+ this.ws.httprequest.tpromise._res();
3041
+ } else {
3042
+ // User is present so we still need consent
3043
+ terminal_consent_ask(this.ws);
3044
+ }
3045
});
2882
- }
2883
- else
2884
- {
3046
+ } else {
3047
+ terminal_consent_ask(this);
3048
+ }
3049
+ } else {
3050
// User-Consent is not required, so just resolve this promise
3051
this.httprequest.tpromise._res();
3052
}
2888
-
2889
-
3053
this.httprequest.tpromise.then(terminal_promise_consent_resolved, terminal_promise_consent_rejected);
3054
}
3055
else if (this.httprequest.protocol == 2)
@@ -2910,6 +3073,7 @@ function onTunnelData(data)
3073
var tsid = null;
3074
if ((this.httprequest.xoptions != null) && (typeof this.httprequest.xoptions.tsid == 'number')) { tsid = this.httprequest.xoptions.tsid; }
3075
require('MeshAgent')._tsid = tsid;
3076
+ this.tsid = tsid;
3077
3078
// If MacOS, Wake up device with caffeinate
3079
if(process.platform == 'darwin'){
@@ -2981,119 +3145,33 @@ function onTunnelData(data)
3145
}
3146
3147
// Perform notification if needed. Toast messages may not be supported on all platforms.
2984
- if (this.httprequest.consent && (this.httprequest.consent & 8))
2985
- {
2986
- // User Consent Prompt is required
2987
- // Send a console message back using the console channel, "\n" is supported.
2988
- this.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: "Waiting for user to grant access...", msgid: 1 }));
2989
- var consentMessage = currentTranslation['desktopConsent'].replace('{0}', this.httprequest.realname).replace('{1}', this.httprequest.username);
2990
- var consentTitle = 'MeshCentral';
2991
- if (this.httprequest.soptions != null)
2992
- {
2993
- if (this.httprequest.soptions.consentTitle != null) { consentTitle = this.httprequest.soptions.consentTitle; }
2994
- if (this.httprequest.soptions.consentMsgDesktop != null) { consentMessage = this.httprequest.soptions.consentMsgDesktop.replace('{0}', this.httprequest.realname).replace('{1}', this.httprequest.username); }
2995
- }
2996
- var pr;
2997
- if (process.platform == 'win32')
2998
- {
2999
- var enhanced = false;
3000
- if (this.httprequest.oldStyle === false) {
3001
- try { require('win-userconsent'); enhanced = true; } catch (ex) { }
3002
- }
3003
- if (enhanced)
3004
- {
3005
- var ipr = server_getUserImage(this.httprequest.userid);
3006
- ipr.consentTitle = consentTitle;
3007
- ipr.consentMessage = consentMessage;
3008
- ipr.consentTimeout = this.httprequest.consentTimeout;
3009
- ipr.consentAutoAccept = this.httprequest.consentAutoAccept;
3010
- ipr.tsid = tsid;
3011
- ipr.username = this.httprequest.realname;
3012
- ipr.translation = { Allow: currentTranslation['allow'], Deny: currentTranslation['deny'], Auto: currentTranslation['autoAllowForFive'], Caption: consentMessage };
3013
- pr = ipr.then(function (img)
3014
- {
3015
- this.consent = require('win-userconsent').create(this.consentTitle, this.consentMessage, this.username, { b64Image: img.split(',').pop(), uid: this.tsid, timeout: this.consentTimeout * 1000, timeoutAutoAccept: this.consentAutoAccept, translations: this.translation, background: color_options.background, foreground: color_options.foreground });
3016
- this.__childPromise.close = this.consent.close.bind(this.consent);
3017
- return (this.consent);
3018
- });
3019
- }
3020
- else
3021
- {
3022
- pr = require('message-box').create(consentTitle, consentMessage, this.httprequest.consentTimeout, null, tsid);
3023
- }
3024
- }
3025
- else
3026
- {
3027
- pr = require('message-box').create(consentTitle, consentMessage, this.httprequest.consentTimeout, null, tsid);
3148
+ if (this.httprequest.consent && (this.httprequest.consent & 8)) {
3149
+
3150
+ // User asked for consent but now we check if can auto accept if no user is present
3151
+ if (this.httprequest.consentAutoAcceptIfNoUser) {
3152
+ // Get list of users to check if we any actual users logged in, and if users logged in, we still need consent
3153
+ var p = require('user-sessions').enumerateUsers();
3154
+ p.sessionid = this.httprequest.sessionid;
3155
+ p.ws = this;
3156
+ p.then(function (u) {
3157
+ var v = [];
3158
+ for (var i in u) {
3159
+ if (u[i].State == 'Active') { v.push({ tsid: i, type: u[i].StationName, user: u[i].Username, domain: u[i].Domain }); }
3160
+ }
3161
+ if (v.length == 0) { // No user is present, auto accept
3162
+ kvm_consent_ok(this.ws);
3163
+ } else {
3164
+ // User is present so we still need consent
3165
+ kvm_consent_ask(this.ws);
3166
+ }
3167
+ });
3168
+ } else {
3169
+ // User Consent Prompt is required
3170
+ kvm_consent_ask(this);
3171
}
3029
- pr.ws = this;
3030
- this.pause();
3031
- this._consentpromise = pr;
3032
- this.prependOnceListener('end', kvm_tunnel_consentpromise_closehandler);
3033
- pr.then(kvm_consentpromise_resolved, kvm_consentpromise_rejected);
3034
- }
3035
- else
3036
- {
3172
+ } else {
3173
// User Consent Prompt is not required
3038
- if (this.httprequest.consent && (this.httprequest.consent & 1))
3039
- {
3040
- // User Notifications is required
3041
- MeshServerLogEx(35, null, "Started remote desktop with toast notification (" + this.httprequest.remoteaddr + ")", this.httprequest);
3042
- var notifyMessage = currentTranslation['desktopNotify'].replace('{0}', this.httprequest.realname);
3043
- var notifyTitle = "MeshCentral";
3044
- if (this.httprequest.soptions != null) {
3045
- if (this.httprequest.soptions.notifyTitle != null) { notifyTitle = this.httprequest.soptions.notifyTitle; }
3046
- if (this.httprequest.soptions.notifyMsgDesktop != null) { notifyMessage = this.httprequest.soptions.notifyMsgDesktop.replace('{0}', this.httprequest.realname).replace('{1}', this.httprequest.username); }
3047
- }
3048
- try { require('toaster').Toast(notifyTitle, notifyMessage, tsid); } catch (ex) { }
3049
- } else
3050
- {
3051
- MeshServerLogEx(36, null, "Started remote desktop without notification (" + this.httprequest.remoteaddr + ")", this.httprequest);
3052
- }
3053
- if (this.httprequest.consent && (this.httprequest.consent & 0x40))
3054
- {
3055
- // Connection Bar is required
3056
- if (this.httprequest.desktop.kvm.connectionBar)
3057
- {
3058
- this.httprequest.desktop.kvm.connectionBar.removeAllListeners('close');
3059
- this.httprequest.desktop.kvm.connectionBar.close();
3060
- }
3061
- try
3062
- {
3063
- this.httprequest.desktop.kvm.connectionBar = require('notifybar-desktop')(this.httprequest.privacybartext.replace('{0}', this.httprequest.desktop.kvm.rusers.join(', ')).replace('{1}', this.httprequest.desktop.kvm.users.join(', ')).replace(/'/g, "\\'\\"), require('MeshAgent')._tsid, color_options);
3064
- MeshServerLogEx(31, null, "Remote Desktop Connection Bar Activated/Updated (" + this.httprequest.remoteaddr + ")", this.httprequest);
3065
- } catch (ex) {
3066
- MeshServerLogEx(32, null, "Remote Desktop Connection Bar Failed or not Supported (" + this.httprequest.remoteaddr + ")", this.httprequest);
3067
- }
3068
- if (this.httprequest.desktop.kvm.connectionBar)
3069
- {
3070
- this.httprequest.desktop.kvm.connectionBar.state =
3071
- {
3072
- userid: this.httprequest.userid,
3073
- xuserid: this.httprequest.xuserid,
3074
- username: this.httprequest.username,
3075
- sessionid: this.httprequest.sessionid,
3076
- remoteaddr: this.httprequest.remoteaddr,
3077
- guestname: this.httprequest.guestname,
3078
- desktop: this.httprequest.desktop
3079
- };
3080
- this.httprequest.desktop.kvm.connectionBar.on('close', function ()
3081
- {
3082
- console.info1('Connection Bar Forcefully closed');
3083
- MeshServerLogEx(29, null, "Remote Desktop Connection forcefully closed by local user (" + this.state.remoteaddr + ")", this.state);
3084
- for (var i in this.state.desktop.kvm._pipedStreams)
3085
- {
3086
- this.state.desktop.kvm._pipedStreams[i].end();
3087
- }
3088
- this.state.desktop.kvm.end();
3089
- });
3090
- }
3091
- }
3092
- this.httprequest.desktop.kvm.pipe(this, { dataTypeSkip: 1 });
3093
- if (this.httprequest.autolock)
3094
- {
3095
- destopLockHelper_pipe(this.httprequest);
3096
- }
3174
+ kvm_consent_ok(this);
3175
}
3176
3177
this.removeAllListeners('data');
@@ -3137,71 +3215,31 @@ function onTunnelData(data)
3215
// Perform notification if needed. Toast messages may not be supported on all platforms.
3216
if (this.httprequest.consent && (this.httprequest.consent & 32))
3217
{
3140
- // User Consent Prompt is required
3141
- // Send a console message back using the console channel, "\n" is supported.
3142
- this.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: "Waiting for user to grant access...", msgid: 1 }));
3143
- var consentMessage = currentTranslation['fileConsent'].replace('{0}', this.httprequest.realname).replace('{1}', this.httprequest.username);
3144
- var consentTitle = 'MeshCentral';
3145
-
3146
- if (this.httprequest.soptions != null)
3147
- {
3148
- if (this.httprequest.soptions.consentTitle != null) { consentTitle = this.httprequest.soptions.consentTitle; }
3149
- if (this.httprequest.soptions.consentMsgFiles != null) { consentMessage = this.httprequest.soptions.consentMsgFiles.replace('{0}', this.httprequest.realname).replace('{1}', this.httprequest.username); }
3150
- }
3151
- var pr;
3152
- if (process.platform == 'win32')
3153
- {
3154
- var enhanced = false;
3155
- if (this.httprequest.oldStyle === false) {
3156
- try { require('win-userconsent'); enhanced = true; } catch (ex) { }
3157
- }
3158
- if (enhanced)
3159
- {
3160
- var ipr = server_getUserImage(this.httprequest.userid);
3161
- ipr.consentTitle = consentTitle;
3162
- ipr.consentMessage = consentMessage;
3163
- ipr.consentTimeout = this.httprequest.consentTimeout;
3164
- ipr.consentAutoAccept = this.httprequest.consentAutoAccept;
3165
- ipr.username = this.httprequest.realname;
3166
- ipr.translations = { Allow: currentTranslation['allow'], Deny: currentTranslation['deny'], Auto: currentTranslation['autoAllowForFive'], Caption: consentMessage };
3167
- pr = ipr.then(function (img)
3168
- {
3169
- this.consent = require('win-userconsent').create(this.consentTitle, this.consentMessage, this.username, { b64Image: img.split(',').pop(), timeout: this.consentTimeout * 1000, timeoutAutoAccept: this.consentAutoAccept, translations: this.translations, background: color_options.background, foreground: color_options.foreground });
3170
- this.__childPromise.close = this.consent.close.bind(this.consent);
3171
- return (this.consent);
3172
- });
3173
- } else
3174
- {
3175
- pr = require('message-box').create(consentTitle, consentMessage, this.httprequest.consentTimeout, null);
3176
- }
3177
- }
3178
- else
3179
- {
3180
- pr = require('message-box').create(consentTitle, consentMessage, this.httprequest.consentTimeout, null);
3181
- }
3182
- pr.ws = this;
3183
- this.pause();
3184
- this._consentpromise = pr;
3185
- this.prependOnceListener('end', files_tunnel_endhandler);
3186
- pr.then(files_consentpromise_resolved, files_consentpromise_rejected);
3187
- }
3188
- else
3189
- {
3190
- // User Consent Prompt is not required
3191
- if (this.httprequest.consent && (this.httprequest.consent & 4)) {
3192
- // User Notifications is required
3193
- MeshServerLogEx(42, null, "Started remote files with toast notification (" + this.httprequest.remoteaddr + ")", this.httprequest);
3194
- var notifyMessage = currentTranslation['fileNotify'].replace('{0}', this.httprequest.realname);
3195
- var notifyTitle = "MeshCentral";
3196
- if (this.httprequest.soptions != null) {
3197
- if (this.httprequest.soptions.notifyTitle != null) { notifyTitle = this.httprequest.soptions.notifyTitle; }
3198
- if (this.httprequest.soptions.notifyMsgFiles != null) { notifyMessage = this.httprequest.soptions.notifyMsgFiles.replace('{0}', this.httprequest.realname).replace('{1}', this.httprequest.username); }
3199
- }
3200
- try { require('toaster').Toast(notifyTitle, notifyMessage); } catch (ex) { }
3218
+ // User asked for consent so now we check if we can auto accept if no user is present/loggedin
3219
+ if (this.httprequest.consentAutoAcceptIfNoUser) {
3220
+ var p = require('user-sessions').enumerateUsers();
3221
+ p.sessionid = this.httprequest.sessionid;
3222
+ p.ws = this;
3223
+ p.then(function (u) {
3224
+ var v = [];
3225
+ for (var i in u) {
3226
+ if (u[i].State == 'Active') { v.push({ tsid: i, type: u[i].StationName, user: u[i].Username, domain: u[i].Domain }); }
3227
+ }
3228
+ if (v.length == 0) { // No user is present, auto accept
3229
+ // User Consent Prompt is not required
3230
+ files_consent_ok(this.ws);
3231
+ } else {
3232
+ // User is present so we still need consent
3233
+ files_consent_ask(this.ws);
3234
+ }
3235
+ });
3236
} else {
3202
- MeshServerLogEx(43, null, "Started remote files without notification (" + this.httprequest.remoteaddr + ")", this.httprequest);
3237
+ // User Consent Prompt is required
3238
+ files_consent_ask(this);
3239
}
3204
- this.resume();
3240
+ } else {
3241
+ // User Consent Prompt is not required
3242
+ files_consent_ok(this);
3243
}
3244
3245
// Setup files
meshcentral-config-schema.json
+5
@@ -1972,6 +1972,11 @@
1972
"default": false,
1973
"description": "If true, user consent is accepted after the timeout."
1974
},
1975
+ "autoAcceptIfNoUser": {
1976
+ "type": "boolean",
1977
+ "default": false,
1978
+ "description": "If true, user consent is accepted if no user is logged in."
1979
+ },
1980
"oldStyle": {
1981
"type": "boolean",
1982
"default": false,
meshdesktopmultiplex.js
+1
@@ -1347,6 +1347,7 @@ function CreateMeshRelayEx2(parent, ws, req, domain, user, cookie) {
1347
if (typeof domain.consentmessages.files == 'string') { command.soptions.consentMsgFiles = domain.consentmessages.files; }
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.oldstyle === true) { command.soptions.oldStyle = true; }
1352
}
1353
if (typeof domain.notificationmessages == 'object') {
meshrelay.js
+4
@@ -896,6 +896,7 @@ function CreateMeshRelayEx(parent, ws, req, domain, user, cookie) {
896
if (typeof domain.consentmessages.files == 'string') { command.soptions.consentMsgFiles = domain.consentmessages.files; }
897
if ((typeof domain.consentmessages.consenttimeout == 'number') && (domain.consentmessages.consenttimeout > 0)) { command.soptions.consentTimeout = domain.consentmessages.consenttimeout; }
898
if (domain.consentmessages.autoacceptontimeout === true) { command.soptions.consentAutoAccept = true; }
899
+ if (domain.consentmessages.autoacceptifnouser === true) { command.soptions.consentAutoAcceptIfNoUser = true; }
900
if (domain.consentmessages.oldstyle === true) { command.soptions.oldStyle = true; }
901
}
902
if (typeof domain.notificationmessages == 'object') {
@@ -934,6 +935,7 @@ function CreateMeshRelayEx(parent, ws, req, domain, user, cookie) {
935
if (typeof domain.consentmessages.files == 'string') { command.soptions.consentMsgFiles = domain.consentmessages.files; }
936
if ((typeof domain.consentmessages.consenttimeout == 'number') && (domain.consentmessages.consenttimeout > 0)) { command.soptions.consentTimeout = domain.consentmessages.consenttimeout; }
937
if (domain.consentmessages.autoacceptontimeout === true) { command.soptions.consentAutoAccept = true; }
938
+ if (domain.consentmessages.autoacceptifnouser === true) { command.soptions.consentAutoAcceptIfNoUser = true; }
939
if (domain.consentmessages.oldstyle === true) { command.soptions.oldStyle = true; }
940
}
941
if (typeof domain.notificationmessages == 'object') {
@@ -952,6 +954,7 @@ function CreateMeshRelayEx(parent, ws, req, domain, user, cookie) {
954
if (typeof domain.consentmessages.files == 'string') { command.soptions.consentMsgFiles = domain.consentmessages.files; }
955
if ((typeof domain.consentmessages.consenttimeout == 'number') && (domain.consentmessages.consenttimeout > 0)) { command.soptions.consentTimeout = domain.consentmessages.consenttimeout; }
956
if (domain.consentmessages.autoacceptontimeout === true) { command.soptions.consentAutoAccept = true; }
957
+ if (domain.consentmessages.autoacceptifnouser === true) { command.soptions.consentAutoAcceptIfNoUser = true; }
958
if (domain.consentmessages.oldstyle === true) { command.soptions.oldStyle = true; }
959
}
960
if (typeof domain.notificationmessages == 'object') {
@@ -1004,6 +1007,7 @@ function CreateMeshRelayEx(parent, ws, req, domain, user, cookie) {
1007
if (typeof domain.consentmessages.files == 'string') { command.soptions.consentMsgFiles = domain.consentmessages.files; }
1008
if ((typeof domain.consentmessages.consenttimeout == 'number') && (domain.consentmessages.consenttimeout > 0)) { command.soptions.consentTimeout = domain.consentmessages.consenttimeout; }
1009
if (domain.consentmessages.autoacceptontimeout === true) { command.soptions.consentAutoAccept = true; }
1010
+ if (domain.consentmessages.autoacceptifnouser === true) { command.soptions.consentAutoAcceptIfNoUser = true; }
1011
if (domain.consentmessages.oldstyle === true) { command.soptions.oldStyle = true; }
1012
}
1013
if (typeof domain.notificationmessages == 'object') {
meshuser.js
+1
@@ -997,6 +997,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
997
if (typeof domain.consentmessages.files == 'string') { command.soptions.consentMsgFiles = domain.consentmessages.files; }
998
if ((typeof domain.consentmessages.consenttimeout == 'number') && (domain.consentmessages.consenttimeout > 0)) { command.soptions.consentTimeout = domain.consentmessages.consenttimeout; }
999
if (domain.consentmessages.autoacceptontimeout === true) { command.soptions.consentAutoAccept = true; }
1000
+ if (domain.consentmessages.autoacceptifnouser === true) { command.soptions.consentAutoAcceptIfNoUser = true; }
1001
if (domain.consentmessages.oldstyle === true) { command.soptions.oldStyle = true; }
1002
}
1003
if (typeof domain.notificationmessages == 'object') {
sample-config-advanced.json
+1
@@ -343,6 +343,7 @@
343
"files": "{0} requesting remote files access. Grant access?",
344
"consentTimeout": 30,
345
"autoAcceptOnTimeout": false,
346
+ "autoAcceptIfNoUser": false,
347
"oldStyle": true
348
},
349
"_notificationMessages": {