Improved web app, SSO fixes.
Ylian Saint-Hilaire committed
May 26, 2020 at 16:36 UTC
b80fe16325162765f233f6691cb059a919642f35
11 files changed
+172
-42
public/android-chrome-192x192.png
Binary files /dev/null and b/public/android-chrome-192x192.png differ
public/android-chrome-512x512.png
Binary files /dev/null and b/public/android-chrome-512x512.png differ
public/favicon-16x16.png
Binary files /dev/null and b/public/favicon-16x16.png differ
public/favicon-32x32.png
Binary files /dev/null and b/public/favicon-32x32.png differ
public/manifest.json
new
+23
@@ -0,0 +1,23 @@
1
+{
2
+ "name": "MeshCentral",
3
+ "short_name": "MeshCentral",
4
+ "description": "Open source web based, remote computer management.",
5
+ "scope": ".",
6
+ "start_url": "/",
7
+ "display": "standalone",
8
+ "orientation": "portrait",
9
+ "theme_color": "#ffffff",
10
+ "background_color": "#ffffff",
11
+ "icons": [
12
+ {
13
+ "src": "android-chrome-192x192.png",
14
+ "sizes": "192x192",
15
+ "type": "image/png"
16
+ },
17
+ {
18
+ "src": "android-chrome-512x512.png",
19
+ "sizes": "512x512",
20
+ "type": "image/png"
21
+ }
22
+ ]
23
+}
\ No newline at end of file
public/styles/style.css
+19
@@ -2833,6 +2833,25 @@ a {
2833
box-shadow: 0px 0px 15px #666;
2834
}
2835
2836
+.suggestionBoxItem {
2837
+ background-color:#5BB;
2838
+ padding: 4px;
2839
+ cursor: pointer;
2840
+ margin-top: 2px;
2841
+ margin-bottom: 2px;
2842
+ border-radius: 4px;
2843
+}
2844
+
2845
+ .suggestionBoxItem:hover {
2846
+ background-color:#4AA;
2847
+ }
2848
+
2849
+.suggestionBoxSubItem {
2850
+ font-size: 11px;
2851
+ margin-left: 4px;
2852
+ color: #555;
2853
+}
2854
+
2855
.traceEvent {
2856
white-space: nowrap;
2857
overflow: hidden;
translate/translate.json
+21
-12
@@ -410,7 +410,7 @@
410
"ru": ", ",
411
"zh-chs": ",",
412
"xloc": [
413
- "default-mobile.handlebars->9->430",
413
+ "default-mobile.handlebars->9->431",
414
"default.handlebars->25->1324"
415
]
416
},
@@ -687,7 +687,7 @@
687
"zh-chs": "1個字節",
688
"xloc": [
689
"default-mobile.handlebars->9->118",
690
- "default-mobile.handlebars->9->434",
690
+ "default-mobile.handlebars->9->435",
691
"default.handlebars->25->1384"
692
]
693
},
@@ -6285,7 +6285,7 @@
6285
"ru": "Подтвердить удаление пользователя {0}?",
6286
"zh-chs": "確認刪除用戶{0}?",
6287
"xloc": [
6288
- "default-mobile.handlebars->9->433"
6288
+ "default-mobile.handlebars->9->434"
6289
]
6290
},
6291
{
@@ -8154,7 +8154,7 @@
8154
"ru": "Пользователь группы устройств",
8155
"zh-chs": "設備組用戶",
8156
"xloc": [
8157
- "default-mobile.handlebars->9->431",
8157
+ "default-mobile.handlebars->9->432",
8158
"default.handlebars->25->1325"
8159
]
8160
},
@@ -19999,7 +19999,7 @@
19999
"ru": "Права",
20000
"zh-chs": "權限",
20001
"xloc": [
20002
- "default-mobile.handlebars->9->429",
20002
+ "default-mobile.handlebars->9->430",
20003
"default.handlebars->25->1323",
20004
"default.handlebars->25->1416"
20005
]
@@ -21388,7 +21388,7 @@
21388
"ru": "Удаленный пользователь Mesh",
21389
"zh-chs": "遠程網狀用戶",
21390
"xloc": [
21391
- "default-mobile.handlebars->9->432"
21391
+ "default-mobile.handlebars->9->433"
21392
]
21393
},
21394
{
@@ -27497,7 +27497,6 @@
27497
"ru": "Пользователь",
27498
"zh-chs": "用戶",
27499
"xloc": [
27500
- "default-mobile.handlebars->9->428",
27500
"default.handlebars->25->1205",
27501
"default.handlebars->25->1428",
27502
"default.handlebars->25->1536",
@@ -27654,6 +27653,12 @@
27653
"default.handlebars->25->1655"
27654
]
27655
},
27656
+ {
27657
+ "en": "User ID",
27658
+ "xloc": [
27659
+ "default-mobile.handlebars->9->429"
27660
+ ]
27661
+ },
27662
{
27663
"cs": "Identifikátor uživatele",
27664
"de": "Benutzeridentifikation",
@@ -27672,6 +27677,13 @@
27677
"default.handlebars->25->1578"
27678
]
27679
},
27680
+ {
27681
+ "en": "User Identifiers",
27682
+ "xloc": [
27683
+ "default.handlebars->25->1259",
27684
+ "default.handlebars->25->1565"
27685
+ ]
27686
+ },
27687
{
27688
"cs": "Export seznamu uživatelů",
27689
"de": "Benutzerlistenexport",
@@ -27703,6 +27715,7 @@
27715
"ru": "Имя пользователя",
27716
"zh-chs": "用戶名",
27717
"xloc": [
27718
+ "default-mobile.handlebars->9->428",
27719
"default.handlebars->25->1321"
27720
]
27721
},
@@ -27718,11 +27731,7 @@
27731
"nl": "Gebruikersnamen",
27732
"pt": "Nomes de usuário",
27733
"ru": "Имена пользователей",
27721
- "zh-chs": "用戶名",
27722
- "xloc": [
27723
- "default.handlebars->25->1259",
27724
- "default.handlebars->25->1565"
27725
- ]
27734
+ "zh-chs": "用戶名"
27735
},
27736
{
27737
"cs": "Uživatelská oprávnění",
views/default-mobile.handlebars
+28
-12
@@ -1,12 +1,18 @@
1
<!DOCTYPE html>
2
<html dir="ltr" xmlns="http://www.w3.org/1999/xhtml">
3
<head>
4
+ <meta charset="utf-8">
5
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
6
<meta content="text/html; charset=utf-8" http-equiv="Content-Type" />
7
<meta name="viewport" content="user-scalable=1.0,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0" />
7
- <meta name="apple-mobile-web-app-capable" content="yes" />
8
<meta name="format-detection" content="telephone=no" />
9
- <link rel="shortcut icon" type="image/x-icon" href="{{{domainurl}}}favicon.ico" />
9
+ <link rel="manifest" href="{{{domainurl}}}manifest.json">
10
+ <link rel="shortcut icon" href="{{{domainurl}}}favicon.ico" />
11
+ <link rel="icon" type="image/png" sizes="16x16" href="{{{domainurl}}}favicon-16x16.png">
12
+ <link rel="icon" type="image/png" sizes="32x32" href="{{{domainurl}}}favicon-32x32.png">
13
+ <meta name="apple-mobile-web-app-capable" content="yes">
14
+ <meta name="apple-mobile-web-app-status-bar-style" content="#ffffff">
15
+ <meta name="apple-mobile-web-app-title" content="{{{title}}}">
16
<script type="text/javascript" src="scripts/common-0.0.1{{{min}}}.js"></script>
17
<script type="text/javascript" src="scripts/meshcentral{{{min}}}.js"></script>
18
<script type="text/javascript" src="scripts/agent-redir-ws-0.1.1{{{min}}}.js"></script>
@@ -19,6 +25,8 @@
25
<script type="text/javascript" src="scripts/zlib-adler32{{{min}}}.js"></script>
26
<script type="text/javascript" src="scripts/zlib-crc32{{{min}}}.js"></script>
27
<script keeplink=1 type="text/javascript" src="scripts/filesaver.min.js"></script>
28
+ <meta name="msapplication-TileColor" content="#00aba9">
29
+ <meta name="theme-color" content="#ffffff">
30
<title>{{{title}}}</title>
31
<style>
32
a {
@@ -263,7 +271,7 @@
271
</div>
272
<img id="topMenuIcon" class=noselect style="position:absolute;right:0;top:10px;bottom:50px;color:#c8c8c8;font-size:44px;margin-right:8px;cursor:pointer;display:none" onclick=topMenu() src="/images/3bars-30.png" width=30 height=30 />
273
</div>
266
- <div id=page_content style="overflow-y:scroll;position:absolute;bottom:32px;top:50px;width:100%">
274
+ <div id=page_content style="position:absolute;bottom:32px;top:50px;width:100%">
275
<div id=column_l style="width:100%;padding:0;position:absolute;bottom:0px;top:0px">
276
<div id=p0 style=display:none;width:100%;height:100%>
277
<div style="display:flex;align-items:center;width:100%;height:100%">
@@ -305,7 +313,7 @@
313
</td>
314
</tr>
315
</table>
308
- <div id=p3info style="overflow-y:scroll;position:absolute;top:55px;bottom:0px;width:100%">
316
+ <div id=p3info style="overflow-y:auto;position:absolute;top:55px;bottom:0px;width:100%">
317
<div style="margin-left:8px">
318
<div id="p3AccountActions">
319
<div id="p2AccountSecurity" style="display:none">
@@ -357,7 +365,7 @@
365
</td>
366
</tr>
367
</table>
360
- <div id=p5myfiles style="overflow-y:scroll;position:absolute;top:55px;bottom:0px;width:100%">
368
+ <div id=p5myfiles style="position:absolute;top:55px;bottom:0px;width:100%">
369
<table id="p5toolbar" style="width:100%;height:78px" cellpadding="0" cellspacing="0">
370
<tr>
371
<td style="width:100%;background-color:#d3d9d6;text-align:left;padding:4px" valign=bottom>
@@ -397,7 +405,7 @@
405
</td>
406
</tr>
407
</table>
400
- <div id="p5filetable" style="width:100%;height:calc(100% - 133px);overflow:auto;-webkit-user-select:none">
408
+ <div id="p5filetable" style="width:100%;height:calc(100% - 102px);overflow:auto;-webkit-user-select:none">
409
<!--
410
<div id="p5bigok" style="width:256px;overflow:hidden;position:absolute;left:337px;top:200px;text-align:center;font-size:1600%;color:#AAAAAA;display:none"><b>✓</b></div>
411
<div id="p5bigfail" style="width:256px;overflow:hidden;position:absolute;left:337px;top:200px;text-align:center;font-size:1600%;color:#AAAAAA;display:none"><b>✗</b></div>
@@ -486,7 +494,7 @@
494
</div>
495
</div>
496
</div>
489
- <div id=p10files style="overflow-y:scroll;position:absolute;top:55px;bottom:0px;width:100%;display:none">
497
+ <div id=p10files style="position:absolute;top:55px;bottom:0px;width:100%;display:none">
498
<table id="p13toolbar" style="width:100%;height:111px" cellpadding="0" cellspacing="0">
499
<tr>
500
<td style="background-color:#C0C0C0;border-bottom:2px solid black;padding:2px">
@@ -553,8 +561,8 @@
561
<div id=p10detailshtml style="margin-left:-3px"></div>
562
</div>
563
</div>
556
- <div id=p20 style=display:none;position:absolute;bottom:0;top:0;width:100%>
557
- <table cellspacing=0 style="margin:0;padding:0;border-spacing:0;border:0;">
564
+ <div id=p20 style="display:none;position:absolute;bottom:0;top:0;width:100%">
565
+ <table cellspacing=0 style="margin:0;padding:0;border-spacing:0;border:0;position:absolute;top:0">
566
<tr style=padding:0>
567
<td style="padding:0;color:#c8c8c8;text-align:center;cursor:pointer" width=60px valign=top onclick=goBack()>
568
<div style="padding:0;background-color:#036;width:10px;height:10px;float:right;border:0">
@@ -572,7 +580,9 @@
580
</td>
581
</tr>
582
</table>
575
- <div id=p20info style="margin-left:8px;margin-right:8px"></div>
583
+ <div style="overflow-y:auto;position:absolute;top:55px;bottom:0px;left:0px;right:0px">
584
+ <div id=p20info style="margin-left:8px;margin-right:8px"></div>
585
+ </div>
586
</div>
587
</div>
588
</div>
@@ -741,6 +751,9 @@
751
QV('manageEmail2FA', features & 0x00800000);
752
QV('managePhoneNumber1', (features & 0x02000000) && (features & 0x04000000));
753
QV('managePhoneNumber2', (features & 0x02000000) && !(features & 0x04000000));
754
+
755
+ attemptWebRTC = 0; // For now, default WebRTC off unless we set it in the URL.
756
+ if (args.webrtc != null) { attemptWebRTC = (args.webrtc == 1); }
757
}
758
759
function onStateChanged(server, state, prevState, errorCode) {
@@ -3779,7 +3792,7 @@
3792
3793
function p20showAddMeshUserDialog() {
3794
if (xxdialogMode) return;
3782
- var x = addHtmlValue('User', '<input id=dp20username style=width:170px maxlength=32 onchange=p20validateAddMeshUserDialog() onkeyup=p20validateAddMeshUserDialog() />');
3795
+ var x = addHtmlValue('User ID', '<input id=dp20username style=width:170px maxlength=256 onchange=p20validateAddMeshUserDialog() onkeyup=p20validateAddMeshUserDialog() />');
3796
x += '<div style="border:2px groove gray;background-color:white;max-height:120px;overflow-y:scroll">';
3797
x += '<label><input type=checkbox onchange=p20validateAddMeshUserDialog() id=p20fulladmin>' + "Full Administrator" + '</label><br>';
3798
x += '<label><input type=checkbox onchange=p20validateAddMeshUserDialog() id=p20editmesh>' + "Edit Device Group" + '</label><br>';
@@ -3874,7 +3887,10 @@
3887
if ((meshrights & 32768) != 0) r.push("Uninstall");
3888
}
3889
if (r.length == 0) { r.push("No Rights"); }
3877
- var buttons = 1, x = addHtmlValue("User", EscapeHtml(decodeURIComponent(userid.split('/')[2])));
3890
+ var buttons = 1, uname = userid.split('/')[2];
3891
+ if (currentMesh.links[userid].name) { uname = currentMesh.links[userid].name; }
3892
+ var x = addHtmlValue("User Name", EscapeHtml(uname));
3893
+ if (uname != userid.split('/')[2]) { x += addHtmlValue("User ID", EscapeHtml(userid.split('/')[2])); }
3894
x += addHtmlValue("Permissions", r.join(", "));
3895
if (((userinfo._id) != userid) && (cmeshrights == 0xFFFFFFFF || (((cmeshrights & 2) != 0) && (meshrights != 0xFFFFFFFF)))) buttons += 4;
3896
setDialogMode(2, "Device Group User", buttons, p20viewuserEx, x, userid);
views/default.handlebars
+22
-6
@@ -8921,7 +8921,7 @@
8921
x += '<br /><br />';
8922
}
8923
x += '<div style=\'position:relative\'>';
8924
- x += addHtmlValue("User Names", '<input id=dp20username style=width:230px maxlength=32 onchange=p20validateAddMeshUserDialog() onkeyup=p20validateAddMeshUserDialog() placeholder="user1, user2, user3" />');
8924
+ x += addHtmlValue("User Identifiers", '<input id=dp20username style=width:230px maxlength=256 onchange=p20validateAddMeshUserDialog() onkeyup=p20validateAddMeshUserDialog() placeholder="user1, user2, user3" />');
8925
x += '<div id=dp20usersuggest class=suggestionBox style=\'top:30px;left:130px;display:none\'></div>';
8926
x += '</div><br>';
8927
} else if (userid == 1) {
@@ -9148,11 +9148,18 @@
9148
if (lastuser.length > 0) {
9149
for (var i in users) {
9150
if (users[i].name === lastuser) { exactMatch = true; break; }
9151
- if (users[i].name.toLowerCase().indexOf(lastuserl) >= 0) { matchingUsers.push(users[i].name); if (matchingUsers.length >= 8) break; }
9151
+ if (users[i].name.toLowerCase().indexOf(lastuserl) >= 0) { matchingUsers.push([users[i]._id, users[i].name]); if (matchingUsers.length >= 8) break; }
9152
}
9153
if ((exactMatch == false) && (matchingUsers.length > 0)) {
9154
var x = '';
9155
- for (var i in matchingUsers) { x += '<a href=# onclick=\'p20setname("' + encodeURIComponentEx(matchingUsers[i]) + '")\'>' + matchingUsers[i] + '</a><br />'; }
9155
+ for (var i in matchingUsers) {
9156
+ var sid = matchingUsers[i][0], sname = matchingUsers[i][1];
9157
+ if (sid.split('/')[2] == sname.toLowerCase()) {
9158
+ x += '<div class=suggestionBoxItem onclick=\'p20setname("' + encodeURIComponentEx(sid.split('/')[2]) + '")\'>' + EscapeHtml(sname) + '</div>';
9159
+ } else {
9160
+ x += '<div class=suggestionBoxItem onclick=\'p20setname("' + encodeURIComponentEx(sid.split('/')[2]) + '")\'><div>' + EscapeHtml(sname) + '</div><div class=suggestionBoxSubItem>' + EscapeHtml(sid.split('/')[2]) + '</div></div>';
9161
+ }
9162
+ }
9163
QH('dp20usersuggest', x);
9164
showsuggestbox = true;
9165
}
@@ -10795,7 +10802,7 @@
10802
var x = "Allow users to manage this device group and devices in this group.";
10803
if (features & 0x00080000) { x += " Users need to login to this server once before they can be added to a device group." }
10804
x += '<br /><br /><div style=\'position:relative\'>';
10798
- x += addHtmlValue("User Names", '<input id=dp51username style=width:230px maxlength=32 onchange=p51validateAddUserDialog() onkeyup=p51validateAddUserDialog() placeholder="user1, user2, user3" />');
10805
+ x += addHtmlValue("User Identifiers", '<input id=dp51username style=width:230px maxlength=32 onchange=p51validateAddUserDialog() onkeyup=p51validateAddUserDialog() placeholder="user1, user2, user3" />');
10806
x += '<div id=dp51usersuggest class=suggestionBox style=\'top:30px;left:130px;display:none\'></div>';
10807
x += '</div><br>';
10808
setDialogMode(2, "Add Users to User Group", 3, p51showAddUserDialogEx, x);
@@ -10817,6 +10824,7 @@
10824
function p51validateAddUserDialog() {
10825
var meshrights = GetMeshRights(currentMesh);
10826
var ok = true;
10827
+
10828
if (Q('dp51username')) {
10829
var xusers = Q('dp51username').value.split(',');
10830
for (var i in xusers) {
@@ -10831,11 +10839,18 @@
10839
if (lastuser.length > 0) {
10840
for (var i in users) {
10841
if (users[i].name === lastuser) { exactMatch = true; break; }
10834
- if (users[i].name.toLowerCase().indexOf(lastuserl) >= 0) { matchingUsers.push(users[i].name); if (matchingUsers.length >= 8) break; }
10842
+ if (users[i].name.toLowerCase().indexOf(lastuserl) >= 0) { matchingUsers.push([users[i]._id, users[i].name]); if (matchingUsers.length >= 8) break; }
10843
}
10844
if ((exactMatch == false) && (matchingUsers.length > 0)) {
10845
var x = '';
10838
- for (var i in matchingUsers) { x += '<a href=# onclick=\'p51setname("' + encodeURIComponentEx(matchingUsers[i]) + '")\'>' + matchingUsers[i] + '</a><br />'; }
10846
+ for (var i in matchingUsers) {
10847
+ var sid = matchingUsers[i][0], sname = matchingUsers[i][1];
10848
+ if (sid.split('/')[2] == sname.toLowerCase()) {
10849
+ x += '<div class=suggestionBoxItem onclick=\'p51setname("' + encodeURIComponentEx(sid.split('/')[2]) + '")\'>' + EscapeHtml(sname) + '</div>';
10850
+ } else {
10851
+ x += '<div class=suggestionBoxItem onclick=\'p51setname("' + encodeURIComponentEx(sid.split('/')[2]) + '")\'><div>' + EscapeHtml(sname) + '</div><div class=suggestionBoxSubItem>' + EscapeHtml(sid.split('/')[2]) + '</div></div>';
10852
+ }
10853
+ }
10854
QH('dp51usersuggest', x);
10855
showsuggestbox = true;
10856
}
@@ -10843,6 +10858,7 @@
10858
}
10859
QV('dp51usersuggest', showsuggestbox);
10860
}
10861
+
10862
QE('idx_dlgOkButton', ok);
10863
}
10864
views/login-mobile.handlebars
+10
-2
@@ -1,14 +1,22 @@
1
<!DOCTYPE html>
2
<html dir="ltr" xmlns="http://www.w3.org/1999/xhtml">
3
<head>
4
+ <meta charset="utf-8">
5
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
6
<meta content="text/html; charset=utf-8" http-equiv="Content-Type" />
7
<meta name="viewport" content="user-scalable=1.0,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0" />
7
- <meta name="apple-mobile-web-app-capable" content="yes" />
8
<meta name="format-detection" content="telephone=no" />
9
- <link rel="shortcut icon" type="image/x-icon" href="{{{domainurl}}}favicon.ico" />
9
+ <link rel="manifest" href="{{{domainurl}}}manifest.json">
10
+ <link rel="shortcut icon" href="{{{domainurl}}}favicon.ico" />
11
+ <link rel="icon" type="image/png" sizes="16x16" href="{{{domainurl}}}favicon-16x16.png">
12
+ <link rel="icon" type="image/png" sizes="32x32" href="{{{domainurl}}}favicon-32x32.png">
13
+ <meta name="apple-mobile-web-app-capable" content="yes">
14
+ <meta name="apple-mobile-web-app-status-bar-style" content="#ffffff">
15
+ <meta name="apple-mobile-web-app-title" content="{{{title}}}">
16
<script type="text/javascript" src="scripts/common-0.0.1{{min}}.js"></script>
17
<script type="text/javascript" src="scripts/u2f-api{{min}}.js"></script>
18
+ <meta name="msapplication-TileColor" content="#00aba9">
19
+ <meta name="theme-color" content="#ffffff">
20
<title>{{{title}}} - Login</title>
21
<style>
22
a {
webserver.js
+49
-10
@@ -4208,7 +4208,13 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
4208
// Twitter
4209
if ((typeof domain.authstrategies.twitter == 'object') && (typeof domain.authstrategies.twitter.clientid == 'string') && (typeof domain.authstrategies.twitter.clientsecret == 'string')) {
4210
const TwitterStrategy = require('passport-twitter');
4211
- passport.use(new TwitterStrategy({ consumerKey: domain.authstrategies.twitter.clientid, consumerSecret: domain.authstrategies.twitter.clientsecret, callbackURL: url + 'auth-twitter-callback' },
4211
+ var options = {
4212
+ consumerKey: domain.authstrategies.twitter.clientid,
4213
+ consumerSecret: domain.authstrategies.twitter.clientsecret,
4214
+ callbackURL: (typeof domain.authstrategies.twitter.callbackurl == 'string') ? domain.authstrategies.twitter.callbackurl : (url + 'auth-twitter-callback')
4215
+ };
4216
+ parent.debug('web', 'Adding Twitter SSO with options: ' + JSON.stringify(options));
4217
+ passport.use(new TwitterStrategy(options,
4218
function (token, tokenSecret, profile, cb) {
4219
parent.debug('web', 'Twitter profile: ' + JSON.stringify(profile));
4220
var user = { sid: '~twitter:' + profile.id, name: profile.displayName, strategy: 'twitter' };
@@ -4239,7 +4245,13 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
4245
// Google
4246
if ((typeof domain.authstrategies.google == 'object') && (typeof domain.authstrategies.google.clientid == 'string') && (typeof domain.authstrategies.google.clientsecret == 'string')) {
4247
const GoogleStrategy = require('passport-google-oauth20');
4242
- passport.use(new GoogleStrategy({ clientID: domain.authstrategies.google.clientid, clientSecret: domain.authstrategies.google.clientsecret, callbackURL: url + 'auth-google-callback' },
4248
+ var options = {
4249
+ clientID: domain.authstrategies.google.clientid,
4250
+ clientSecret: domain.authstrategies.google.clientsecret,
4251
+ callbackURL: (typeof domain.authstrategies.google.callbackurl == 'string') ? domain.authstrategies.google.callbackurl : (url + 'auth-google-callback')
4252
+ };
4253
+ parent.debug('web', 'Adding Google SSO with options: ' + JSON.stringify(options));
4254
+ passport.use(new GoogleStrategy(options,
4255
function (token, tokenSecret, profile, cb) {
4256
parent.debug('web', 'Google profile: ' + JSON.stringify(profile));
4257
var user = { sid: '~google:' + profile.id, name: profile.displayName, strategy: 'google' };
@@ -4262,7 +4274,13 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
4274
// Github
4275
if ((typeof domain.authstrategies.github == 'object') && (typeof domain.authstrategies.github.clientid == 'string') && (typeof domain.authstrategies.github.clientsecret == 'string')) {
4276
const GitHubStrategy = require('passport-github2');
4265
- passport.use(new GitHubStrategy({ clientID: domain.authstrategies.github.clientid, clientSecret: domain.authstrategies.github.clientsecret, callbackURL: url + 'auth-github-callback' },
4277
+ var options = {
4278
+ clientID: domain.authstrategies.github.clientid,
4279
+ clientSecret: domain.authstrategies.github.clientsecret,
4280
+ callbackURL: (typeof domain.authstrategies.github.callbackurl == 'string') ? domain.authstrategies.github.callbackurl : (url + 'auth-github-callback')
4281
+ };
4282
+ parent.debug('web', 'Adding Github SSO with options: ' + JSON.stringify(options));
4283
+ passport.use(new GitHubStrategy(options,
4284
function (token, tokenSecret, profile, cb) {
4285
parent.debug('web', 'Github profile: ' + JSON.stringify(profile));
4286
var user = { sid: '~github:' + profile.id, name: profile.displayName, strategy: 'github' };
@@ -4285,7 +4303,13 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
4303
// Reddit
4304
if ((typeof domain.authstrategies.reddit == 'object') && (typeof domain.authstrategies.reddit.clientid == 'string') && (typeof domain.authstrategies.reddit.clientsecret == 'string')) {
4305
const RedditStrategy = require('passport-reddit');
4288
- passport.use(new RedditStrategy.Strategy({ clientID: domain.authstrategies.reddit.clientid, clientSecret: domain.authstrategies.reddit.clientsecret, callbackURL: url + 'auth-reddit-callback' },
4306
+ var options = {
4307
+ clientID: domain.authstrategies.reddit.clientid,
4308
+ clientSecret: domain.authstrategies.reddit.clientsecret,
4309
+ callbackURL: (typeof domain.authstrategies.reddit.callbackurl == 'string') ? domain.authstrategies.reddit.callbackurl : (url + 'auth-reddit-callback')
4310
+ };
4311
+ parent.debug('web', 'Adding Reddit SSO with options: ' + JSON.stringify(options));
4312
+ passport.use(new RedditStrategy.Strategy(options,
4313
function (token, tokenSecret, profile, cb) {
4314
parent.debug('web', 'Reddit profile: ' + JSON.stringify(profile));
4315
var user = { sid: '~reddit:' + profile.id, name: profile.name, strategy: 'reddit' };
@@ -4323,12 +4347,14 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
4347
// Azure
4348
if ((typeof domain.authstrategies.azure == 'object') && (typeof domain.authstrategies.azure.clientid == 'string') && (typeof domain.authstrategies.azure.clientsecret == 'string')) {
4349
const AzureOAuth2Strategy = require('passport-azure-oauth2');
4326
- passport.use('azure', new AzureOAuth2Strategy({
4350
+ var options = {
4351
clientID: domain.authstrategies.azure.clientid,
4352
clientSecret: domain.authstrategies.azure.clientsecret,
4353
tenant: domain.authstrategies.azure.tenantid,
4330
- callbackURL: url + 'auth-azure-callback'
4331
- },
4354
+ callbackURL: (typeof domain.authstrategies.azure.callbackurl == 'string') ? domain.authstrategies.azure.callbackurl : (url + 'auth-azure-callback')
4355
+ };
4356
+ parent.debug('web', 'Adding Azure SSO with options: ' + JSON.stringify(options));
4357
+ passport.use('azure', new AzureOAuth2Strategy(options,
4358
function (accessToken, refreshtoken, params, profile, done) {
4359
var userex = null;
4360
try { userex = require('jwt-simple').decode(params.id_token, "", true); } catch (ex) { }
@@ -4377,7 +4403,11 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
4403
if (cert == null) {
4404
console.log('ERROR: Unable to read SAML IdP certificate: ' + domain.authstrategies.saml.cert);
4405
} else {
4380
- var options = { path: url + 'auth-saml-callback', entryPoint: domain.authstrategies.saml.idpurl, issuer: 'meshcentral' };
4406
+ var options = {
4407
+ path: (typeof domain.authstrategies.saml.callbackurl == 'string') ? domain.authstrategies.saml.callbackurl : (url + 'auth-saml-callback'),
4408
+ entryPoint: domain.authstrategies.saml.idpurl, issuer: 'meshcentral'
4409
+ };
4410
+ parent.debug('web', 'Adding SAML SSO with options: ' + JSON.stringify(options));
4411
if (typeof domain.authstrategies.saml.entityid == 'string') { options.issuer = domain.authstrategies.saml.entityid; }
4412
options.cert = cert.toString().split('-----BEGIN CERTIFICATE-----').join('').split('-----END CERTIFICATE-----').join('');
4413
const SamlStrategy = require('passport-saml').Strategy;
@@ -4414,7 +4444,11 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
4444
if (cert == null) {
4445
console.log('ERROR: Unable to read Intel SAML IdP certificate: ' + domain.authstrategies.intel.cert);
4446
} else {
4417
- var options = { path: url + 'auth-intel-callback', entryPoint: domain.authstrategies.intel.idpurl, issuer: 'meshcentral' };
4447
+ var options = {
4448
+ path: (typeof domain.authstrategies.intel.callbackurl == 'string') ? domain.authstrategies.intel.callbackurl : (url + 'auth-intel-callback'),
4449
+ entryPoint: domain.authstrategies.intel.idpurl, issuer: 'meshcentral'
4450
+ };
4451
+ parent.debug('web', 'Adding Intel SSO with options: ' + JSON.stringify(options));
4452
if (typeof domain.authstrategies.intel.entityid == 'string') { options.issuer = domain.authstrategies.intel.entityid; }
4453
options.cert = cert.toString().split('-----BEGIN CERTIFICATE-----').join('').split('-----END CERTIFICATE-----').join('');
4454
const SamlStrategy = require('passport-saml').Strategy;
@@ -4453,7 +4487,11 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
4487
if (cert == null) {
4488
console.log('ERROR: Unable to read JumpCloud IdP certificate: ' + domain.authstrategies.jumpcloud.cert);
4489
} else {
4456
- var options = { path: url + 'auth-jumpcloud-callback', entryPoint: domain.authstrategies.jumpcloud.idpurl, issuer: 'meshcentral' };
4490
+ var options = {
4491
+ path: (typeof domain.authstrategies.jumpcloud.callbackurl == 'string') ? domain.authstrategies.jumpcloud.callbackurl : (url + 'auth-jumpcloud-callback'),
4492
+ entryPoint: domain.authstrategies.jumpcloud.idpurl, issuer: 'meshcentral'
4493
+ };
4494
+ parent.debug('web', 'Adding JumpCloud SSO with options: ' + JSON.stringify(options));
4495
if (typeof domain.authstrategies.jumpcloud.entityid == 'string') { options.issuer = domain.authstrategies.jumpcloud.entityid; }
4496
options.cert = cert.toString().split('-----BEGIN CERTIFICATE-----').join('').split('-----END CERTIFICATE-----').join('');
4497
const SamlStrategy = require('passport-saml').Strategy;
@@ -5368,6 +5406,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
5406
// Return the correct render page given mobile, minify and override path.
5407
function getRenderPage(pagename, req, domain) {
5408
var mobile = isMobileBrowser(req), minify = (domain.minify == true), p;
5409
+ if (req.query.mobile == '1') { mobile = true; } else if (req.query.mobile == '0') { mobile = false; }
5410
if (req.query.minify == '1') { minify = true; } else if (req.query.minify == '0') { minify = false; }
5411
if (mobile) {
5412
if ((domain != null) && (domain.webviewspath != null)) { // If the domain has a web views path, use that first