mirror of
https://github.com/Ylianst/MeshCentral.git
synced 2025-02-12 11:01:52 +00:00
Improved Windows agent crash logs and mobile phone login page
This commit is contained in:
parent
328a6ff4d6
commit
098841fdc1
12 changed files with 129 additions and 143 deletions
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "meshcentral",
|
"name": "meshcentral",
|
||||||
"version": "0.1.7-r",
|
"version": "0.1.7-s",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"Remote Management",
|
"Remote Management",
|
||||||
"Intel AMT",
|
"Intel AMT",
|
||||||
|
|
BIN
public/images/mainwelcome-90.png
Normal file
BIN
public/images/mainwelcome-90.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 12 KiB |
|
@ -29,23 +29,19 @@
|
||||||
<div id=container>
|
<div id=container>
|
||||||
<div id=mastheadx></div>
|
<div id=mastheadx></div>
|
||||||
<div id=masthead style="background-color:#036;background-repeat:no-repeat;height:50px;width:100%;overflow:hidden">
|
<div id=masthead style="background-color:#036;background-repeat:no-repeat;height:50px;width:100%;overflow:hidden">
|
||||||
<div style="float:left;height:66px;color:#c8c8c8;padding-left:10px;padding-top:4px">
|
<div style="float:left;height:66px;color:#c8c8c8;padding-left:10px;padding-top:6px">
|
||||||
<strong><font style="font-size:36px;font-family:Arial,Helvetica,sans-serif">{{{title}}}</font></strong>
|
<strong><font style="font-size:36px;font-family:Arial,Helvetica,sans-serif">{{{title}}}</font></strong>
|
||||||
</div>
|
</div>
|
||||||
<div style="float:left;height:66px;color:#c8c8c8;padding-left:5px;padding-top:7px">
|
<div style="float:left;height:66px;color:#c8c8c8;padding-left:5px;padding-top:10px">
|
||||||
<strong><font style="font-size:12px;font-family:Arial,Helvetica,sans-serif">{{{title2}}}</font></strong>
|
<strong><font style="font-size:12px;font-family:Arial,Helvetica,sans-serif">{{{title2}}}</font></strong>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id=page_content style="overflow-y:scroll;position:absolute;bottom:32px;top:50px">
|
<div id=page_content style="overflow-y:scroll;position:absolute;bottom:32px;top:50px;width:100%;display:flex;align-items:center">
|
||||||
<div id=column_l style="padding:10px">
|
<div id=column_l style="padding:10px;width:100%">
|
||||||
<div align=center>
|
<table style="width:100%">
|
||||||
<img alt="" src=images/icons50.png width=300 height=50 />
|
|
||||||
</div>
|
|
||||||
<p>Connect to your devices anywhere using MeshCentral, the remote monitoring and management web site. Get started by creating an account if you don't have one already.</p>
|
|
||||||
<table style=width:100%>
|
|
||||||
<tr>
|
<tr>
|
||||||
<td align=center>
|
<td align=center>
|
||||||
<div id=loginpanel style="background-color:#979797;border-radius:16px;width:260px;padding:16px;text-align:center;display:none">
|
<div id=loginpanel style="background-color:#979797;border-radius:16px;width:260px;padding:16px;text-align:center;clear:both;display:none">
|
||||||
<form action="login" method=post>
|
<form action="login" method=post>
|
||||||
<div id=message1>
|
<div id=message1>
|
||||||
{{{message}}}
|
{{{message}}}
|
||||||
|
@ -76,50 +72,52 @@
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<div id=createpanel style="background-color: #979797;border-radius:16px;width:260px;padding:16px;text-align:center;display:none">
|
<div id=createpanel style="display:none">
|
||||||
<form action=createaccount method=post>
|
<div style="background-color: #979797;border-radius:16px;width:260px;padding:16px;text-align:center;clear:both">
|
||||||
<div id=message2>
|
<form action=createaccount method=post>
|
||||||
{{{message}}}
|
<div id=message2>
|
||||||
</div>
|
{{{message}}}
|
||||||
<div>
|
</div>
|
||||||
<b>Account Creation</b>
|
<div>
|
||||||
</div>
|
<b>Account Creation</b>
|
||||||
<table>
|
</div>
|
||||||
<tr>
|
<table>
|
||||||
<td align=right width=100>Username:</td>
|
<tr>
|
||||||
<td><input id=ausername type=text name=username onchange=validateCreate(1) maxlength=64 onkeydown=haltReturn(event) onkeyup=validateCreate(1,event) /></td>
|
<td align=right width=100>Username:</td>
|
||||||
</tr>
|
<td><input id=ausername type=text name=username onchange=validateCreate(1) maxlength=64 onkeydown=haltReturn(event) onkeyup=validateCreate(1,event) /></td>
|
||||||
<tr>
|
</tr>
|
||||||
<td align=right width=100>Email:</td>
|
<tr>
|
||||||
<td><input id=aemail type=text name=email onchange=validateCreate(2) maxlength=256 onkeydown=haltReturn(event) onkeyup=validateCreate(2,event) /></td>
|
<td align=right width=100>Email:</td>
|
||||||
</tr>
|
<td><input id=aemail type=text name=email onchange=validateCreate(2) maxlength=256 onkeydown=haltReturn(event) onkeyup=validateCreate(2,event) /></td>
|
||||||
<tr>
|
</tr>
|
||||||
<td align=right>Password:</td>
|
<tr>
|
||||||
<td><input id=apassword1 type=password name=password1 autocomplete=off maxlength=256 onkeydown=haltReturn(event) onchange=validateCreate(3) onkeyup=validateCreate(3,event) /></td>
|
<td align=right>Password:</td>
|
||||||
</tr>
|
<td><input id=apassword1 type=password name=password1 autocomplete=off maxlength=256 onkeydown=haltReturn(event) onchange=validateCreate(3) onkeyup=validateCreate(3,event) /></td>
|
||||||
<tr>
|
</tr>
|
||||||
<td align=right>Password:</td>
|
<tr>
|
||||||
<td><input id=apassword2 type=password name=password2 autocomplete=off maxlength=256 onkeydown=haltReturn(event) onchange=validateCreate(4) onkeyup=validateCreate(4,event) /></td>
|
<td align=right>Password:</td>
|
||||||
</tr>
|
<td><input id=apassword2 type=password name=password2 autocomplete=off maxlength=256 onkeydown=haltReturn(event) onchange=validateCreate(4) onkeyup=validateCreate(4,event) /></td>
|
||||||
<tr>
|
</tr>
|
||||||
<td align=right>Pass Hint:</td>
|
<tr>
|
||||||
<td><input id=apasswordhint type=text name=apasswordhint autocomplete=off maxlength=256 onkeydown=haltReturn(event) onchange=validateCreate(5) onkeyup=validateCreate(5,event) /></td>
|
<td align=right>Pass Hint:</td>
|
||||||
</tr>
|
<td><input id=apasswordhint type=text name=apasswordhint autocomplete=off maxlength=256 onkeydown=haltReturn(event) onchange=validateCreate(5) onkeyup=validateCreate(5,event) /></td>
|
||||||
<tr id=newAccountPass title="Enter the account creation token">
|
</tr>
|
||||||
<td align=right>Creation Token:</td>
|
<tr id=newAccountPass title="Enter the account creation token">
|
||||||
<td><input id=anewaccountpass type=password name=anewaccountpass autocomplete=off maxlength=256 onkeydown=haltReturn(event) onchange=validateCreate(6) onkeyup=validateCreate(6,event) /></td>
|
<td align=right>Creation Token:</td>
|
||||||
</tr>
|
<td><input id=anewaccountpass type=password name=anewaccountpass autocomplete=off maxlength=256 onkeydown=haltReturn(event) onchange=validateCreate(6) onkeyup=validateCreate(6,event) /></td>
|
||||||
<tr>
|
</tr>
|
||||||
<td colspan=2>
|
<tr>
|
||||||
<div style=float:right><input id=createButton type=submit value="Create Account" disabled="disabled" /></div>
|
<td colspan=2>
|
||||||
<div id=passWarning style="padding-top:6px"></div>
|
<div style=float:right><input id=createButton type=submit value="Create Account" disabled="disabled" /></div>
|
||||||
</td>
|
<div id=passWarning style="padding-top:6px"></div>
|
||||||
</tr>
|
</td>
|
||||||
</table>
|
</tr>
|
||||||
<hr /><a onclick=xgo(1) style=cursor:pointer>Back to login</a>
|
</table>
|
||||||
</form>
|
<hr /><a onclick=xgo(1) style=cursor:pointer>Back to login</a>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id=resetpanel style="background-color: #979797;border-radius:16px;width:260px;padding:16px;text-align:center;display:none">
|
<div id=resetpanel style="background-color: #979797;border-radius:16px;width:260px;padding:16px;text-align:center;display:none;clear:both">
|
||||||
<form action=resetaccount method=post>
|
<form action=resetaccount method=post>
|
||||||
<div id=message3>
|
<div id=message3>
|
||||||
{{{message}}}
|
{{{message}}}
|
||||||
|
|
|
@ -24,7 +24,7 @@
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body onload="if (typeof(startup) !== 'undefined') startup();" style="overflow-y:hidden;margin:0;padding:0;border:0;color:black;font-size:13px;font-family:\'Trebuchet MS\', Arial, Helvetica, sans-serif">
|
<body onload="if (typeof(startup) !== 'undefined') startup();" style="overflow-y:hidden;max-width:100%;margin:0;padding:0;border:0;color:black;font-size:13px;font-family:\'Trebuchet MS\', Arial, Helvetica, sans-serif">
|
||||||
<div id="container">
|
<div id="container">
|
||||||
<!-- Begin Masthead -->
|
<!-- Begin Masthead -->
|
||||||
<div id=masthead style="background-color:#036;background-repeat:no-repeat;height:50px;width:100%;overflow:hidden">
|
<div id=masthead style="background-color:#036;background-repeat:no-repeat;height:50px;width:100%;overflow:hidden">
|
||||||
|
@ -146,12 +146,6 @@
|
||||||
<p class="MsoNormal">
|
<p class="MsoNormal">
|
||||||
<span>This software uses code from <a href="http://www.webtoolkit.info/javascript-base64.html">http://www.webtoolkit.info/javascript-base64.html</a> licensed under the <a href="http://creativecommons.org/licenses/by/2.0/uk/legalcode">http://creativecommons.org/licenses/by/2.0/uk/legalcode</a> and its source can be downloaded from <a href="http://www.webtoolkit.info/javascript-base64.html">http://www.webtoolkit.info/javascript-base64.html</a>.<o:p></o:p></span>
|
<span>This software uses code from <a href="http://www.webtoolkit.info/javascript-base64.html">http://www.webtoolkit.info/javascript-base64.html</a> licensed under the <a href="http://creativecommons.org/licenses/by/2.0/uk/legalcode">http://creativecommons.org/licenses/by/2.0/uk/legalcode</a> and its source can be downloaded from <a href="http://www.webtoolkit.info/javascript-base64.html">http://www.webtoolkit.info/javascript-base64.html</a>.<o:p></o:p></span>
|
||||||
</p>
|
</p>
|
||||||
<p class="MsoNormal">
|
|
||||||
<b>8.Android LibJPEG</b>
|
|
||||||
</p>
|
|
||||||
<p class="MsoNormal">
|
|
||||||
This software uses code from <span style="color:#1F497D"><a href="https://github.com/android/platform_external_jpeg">https://github.com/android/platform_external_jpeg</a> </span>licensed under<span style="color:#1F497D"> <a href="https://github.com/android/platform_external_jpeg/blob/master/NOTICE">https://github.com/android/platform_external_jpeg/blob/master/NOTICE</a><o:p></o:p></span>
|
|
||||||
</p>
|
|
||||||
<br />
|
<br />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -159,7 +153,7 @@
|
||||||
<table cellpadding=0 cellspacing=6 style=width:100%>
|
<table cellpadding=0 cellspacing=6 style=width:100%>
|
||||||
<tr>
|
<tr>
|
||||||
<td style=text-align:left;color:white>{{{footer}}}</td>
|
<td style=text-align:left;color:white>{{{footer}}}</td>
|
||||||
<td style=text-align:right>{{{rootCertLink}}} <a href="/">Login</a></td>
|
<td style=text-align:right>{{{rootCertLink}}} <a href="/">Back</a></td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -131,12 +131,6 @@
|
||||||
<p class="MsoNormal">
|
<p class="MsoNormal">
|
||||||
<span>This software uses code from <a href="http://www.webtoolkit.info/javascript-base64.html">http://www.webtoolkit.info/javascript-base64.html</a> licensed under the <a href="http://creativecommons.org/licenses/by/2.0/uk/legalcode">http://creativecommons.org/licenses/by/2.0/uk/legalcode</a> and its source can be downloaded from <a href="http://www.webtoolkit.info/javascript-base64.html">http://www.webtoolkit.info/javascript-base64.html</a>.<o:p></o:p></span>
|
<span>This software uses code from <a href="http://www.webtoolkit.info/javascript-base64.html">http://www.webtoolkit.info/javascript-base64.html</a> licensed under the <a href="http://creativecommons.org/licenses/by/2.0/uk/legalcode">http://creativecommons.org/licenses/by/2.0/uk/legalcode</a> and its source can be downloaded from <a href="http://www.webtoolkit.info/javascript-base64.html">http://www.webtoolkit.info/javascript-base64.html</a>.<o:p></o:p></span>
|
||||||
</p>
|
</p>
|
||||||
<p class="MsoNormal">
|
|
||||||
<b>8.Android LibJPEG</b>
|
|
||||||
</p>
|
|
||||||
<p class="MsoNormal">
|
|
||||||
This software uses code from <span style="color:#1F497D"><a href="https://github.com/android/platform_external_jpeg">https://github.com/android/platform_external_jpeg</a> </span>licensed under<span style="color:#1F497D"> <a href="https://github.com/android/platform_external_jpeg/blob/master/NOTICE">https://github.com/android/platform_external_jpeg/blob/master/NOTICE</a><o:p></o:p></span>
|
|
||||||
</p>
|
|
||||||
<br />
|
<br />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -144,7 +138,7 @@
|
||||||
<table cellpadding="0" cellspacing="10" style="width: 100%">
|
<table cellpadding="0" cellspacing="10" style="width: 100%">
|
||||||
<tr>
|
<tr>
|
||||||
<td style="text-align:left"></td>
|
<td style="text-align:left"></td>
|
||||||
<td style="text-align:right"><a href="/">Login</a></td>
|
<td style="text-align:right"><a href="/">Back</a></td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|
148
webserver.js
148
webserver.js
|
@ -55,7 +55,7 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
|
||||||
obj.meshRelayHandler = require('./meshrelay.js')
|
obj.meshRelayHandler = require('./meshrelay.js')
|
||||||
obj.meshUserHandler = require('./meshuser.js')
|
obj.meshUserHandler = require('./meshuser.js')
|
||||||
obj.interceptor = require('./interceptor');
|
obj.interceptor = require('./interceptor');
|
||||||
|
|
||||||
// Variables
|
// Variables
|
||||||
obj.parent = parent;
|
obj.parent = parent;
|
||||||
obj.filespath = parent.filespath;
|
obj.filespath = parent.filespath;
|
||||||
|
@ -119,7 +119,7 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
|
||||||
obj.sessionsCount = {}; // Merged session counters, used when doing server peering. UserId --> SessionCount
|
obj.sessionsCount = {}; // Merged session counters, used when doing server peering. UserId --> SessionCount
|
||||||
obj.wsrelays = {}; // Id -> Relay
|
obj.wsrelays = {}; // Id -> Relay
|
||||||
obj.wsPeerRelays = {}; // Id -> { ServerId, Time }
|
obj.wsPeerRelays = {}; // Id -> { ServerId, Time }
|
||||||
|
|
||||||
// Setup randoms
|
// Setup randoms
|
||||||
obj.crypto.randomBytes(48, function (err, buf) { obj.httpAuthRandom = buf; });
|
obj.crypto.randomBytes(48, function (err, buf) { obj.httpAuthRandom = buf; });
|
||||||
obj.crypto.randomBytes(16, function (err, buf) { obj.httpAuthRealm = buf.toString('hex'); });
|
obj.crypto.randomBytes(16, function (err, buf) { obj.httpAuthRealm = buf.toString('hex'); });
|
||||||
|
@ -147,7 +147,7 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
|
||||||
obj.tlsServer = require('https').createServer(tlsOptions, obj.app);
|
obj.tlsServer = require('https').createServer(tlsOptions, obj.app);
|
||||||
obj.expressWs = require('express-ws')(obj.app, obj.tlsServer);
|
obj.expressWs = require('express-ws')(obj.app, obj.tlsServer);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Setup middleware
|
// Setup middleware
|
||||||
obj.app.engine('handlebars', obj.exphbs({})); // defaultLayout: 'main'
|
obj.app.engine('handlebars', obj.exphbs({})); // defaultLayout: 'main'
|
||||||
obj.app.set('view engine', 'handlebars');
|
obj.app.set('view engine', 'handlebars');
|
||||||
|
@ -157,7 +157,7 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
|
||||||
saveUninitialized: false, // don't create session until something stored
|
saveUninitialized: false, // don't create session until something stored
|
||||||
secret: secret // If multiple instances of this server are behind a load-balancer, this secret must be the same for all instances
|
secret: secret // If multiple instances of this server are behind a load-balancer, this secret must be the same for all instances
|
||||||
}));
|
}));
|
||||||
|
|
||||||
// Session-persisted message middleware
|
// Session-persisted message middleware
|
||||||
obj.app.use(function (req, res, next) {
|
obj.app.use(function (req, res, next) {
|
||||||
if (req.session != null) {
|
if (req.session != null) {
|
||||||
|
@ -187,7 +187,7 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Fetch all meshes from the database, keep this in memory
|
// Fetch all meshes from the database, keep this in memory
|
||||||
obj.db.GetAllType('mesh', function (err, docs) { for (var i in docs) { obj.meshes[docs[i]._id] = docs[i]; } });
|
obj.db.GetAllType('mesh', function (err, docs) { for (var i in docs) { obj.meshes[docs[i]._id] = docs[i]; } });
|
||||||
|
|
||||||
|
@ -279,7 +279,7 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
|
||||||
if ((d != null) && (d.dns == null)) return parent.config.domains[x[1].toLowerCase()];
|
if ((d != null) && (d.dns == null)) return parent.config.domains[x[1].toLowerCase()];
|
||||||
return parent.config.domains[''];
|
return parent.config.domains[''];
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleLogoutRequest(req, res) {
|
function handleLogoutRequest(req, res) {
|
||||||
var domain = checkUserIpAddress(req, res);
|
var domain = checkUserIpAddress(req, res);
|
||||||
if (domain == null) return;
|
if (domain == null) return;
|
||||||
|
@ -293,7 +293,7 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
|
||||||
res.redirect(domain.url);
|
res.redirect(domain.url);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleLoginRequest(req, res) {
|
function handleLoginRequest(req, res) {
|
||||||
var domain = checkUserIpAddress(req, res);
|
var domain = checkUserIpAddress(req, res);
|
||||||
if (domain == null) return;
|
if (domain == null) return;
|
||||||
|
@ -345,7 +345,7 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleCreateAccountRequest(req, res) {
|
function handleCreateAccountRequest(req, res) {
|
||||||
var domain = checkUserIpAddress(req, res);
|
var domain = checkUserIpAddress(req, res);
|
||||||
if (domain == null) return;
|
if (domain == null) return;
|
||||||
|
@ -479,7 +479,7 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
|
||||||
res.render(obj.path.join(__dirname, 'views/message'), { title: domain.title, title2: domain.title2, title3: 'Account Verification', message: 'Verified email <b>' + EscapeHtml(user.email) + '</b> for user account <b>' + EscapeHtml(user.name) + '</b>. <a href="' + domain.url + '">Go to login page</a>.' });
|
res.render(obj.path.join(__dirname, 'views/message'), { title: domain.title, title2: domain.title2, title3: 'Account Verification', message: 'Verified email <b>' + EscapeHtml(user.email) + '</b> for user account <b>' + EscapeHtml(user.name) + '</b>. <a href="' + domain.url + '">Go to login page</a>.' });
|
||||||
|
|
||||||
// Send a notification
|
// Send a notification
|
||||||
obj.parent.DispatchEvent([user._id], obj, { action: 'notify', value: 'Email verified:<br /><b>' + EscapeHtml(userinfo.email) + '</b>.' , nolog: 1 })
|
obj.parent.DispatchEvent([user._id], obj, { action: 'notify', value: 'Email verified:<br /><b>' + EscapeHtml(userinfo.email) + '</b>.', nolog: 1 })
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -538,7 +538,7 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
|
||||||
if (!req.session || !req.session.userid || !req.body.apassword1 || (req.body.apassword1 != req.body.apassword2) || (req.session.domainid != domain.id)) { res.redirect(domain.url); return; }
|
if (!req.session || !req.session.userid || !req.body.apassword1 || (req.body.apassword1 != req.body.apassword2) || (req.session.domainid != domain.id)) { res.redirect(domain.url); return; }
|
||||||
var user = obj.users[req.session.userid];
|
var user = obj.users[req.session.userid];
|
||||||
if (!user) return;
|
if (!user) return;
|
||||||
|
|
||||||
// Check if the password is correct
|
// Check if the password is correct
|
||||||
obj.authenticate(user.name, req.body.apassword1, domain, function (err, userid) {
|
obj.authenticate(user.name, req.body.apassword1, domain, function (err, userid) {
|
||||||
var user = obj.users[userid];
|
var user = obj.users[userid];
|
||||||
|
@ -571,14 +571,14 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle password changes
|
// Handle password changes
|
||||||
function handlePasswordChangeRequest(req, res) {
|
function handlePasswordChangeRequest(req, res) {
|
||||||
var domain = checkUserIpAddress(req, res);
|
var domain = checkUserIpAddress(req, res);
|
||||||
if (domain == null) return;
|
if (domain == null) return;
|
||||||
// Check if the user is logged and we have all required parameters
|
// Check if the user is logged and we have all required parameters
|
||||||
if (!req.session || !req.session.userid || !req.body.apassword1 || (req.body.apassword1 != req.body.apassword2) || (req.session.domainid != domain.id)) { res.redirect(domain.url); return; }
|
if (!req.session || !req.session.userid || !req.body.apassword1 || (req.body.apassword1 != req.body.apassword2) || (req.session.domainid != domain.id)) { res.redirect(domain.url); return; }
|
||||||
|
|
||||||
// Update the password
|
// Update the password
|
||||||
require('./pass').hash(req.body.apassword1, function (err, salt, hash) {
|
require('./pass').hash(req.body.apassword1, function (err, salt, hash) {
|
||||||
if (err) throw err;
|
if (err) throw err;
|
||||||
|
@ -708,7 +708,7 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
|
||||||
if (obj.args.webrtc == true) { features += 128; } // Enable WebRTC (Default false for now)
|
if (obj.args.webrtc == true) { features += 128; } // Enable WebRTC (Default false for now)
|
||||||
if (obj.args.clickonce !== false) { features += 256; } // Enable ClickOnce (Default true)
|
if (obj.args.clickonce !== false) { features += 256; } // Enable ClickOnce (Default true)
|
||||||
if (obj.args.allowhighqualitydesktop == true) { features += 512; } // Enable AllowHighQualityDesktop (Default false)
|
if (obj.args.allowhighqualitydesktop == true) { features += 512; } // Enable AllowHighQualityDesktop (Default false)
|
||||||
|
|
||||||
// Send the master web application
|
// Send the master web application
|
||||||
if ((!obj.args.user) && (obj.args.nousers != true) && (nologout == false)) { logoutcontrol += ' <a href=' + domain.url + 'logout?' + Math.random() + ' style=color:white>Logout</a>'; } // If a default user is in use or no user mode, don't display the logout button
|
if ((!obj.args.user) && (obj.args.nousers != true) && (nologout == false)) { logoutcontrol += ' <a href=' + domain.url + 'logout?' + Math.random() + ' style=color:white>Logout</a>'; } // If a default user is in use or no user mode, don't display the logout button
|
||||||
var httpsPort = ((obj.args.aliasport == null) ? obj.args.port : obj.args.aliasport); // Use HTTPS alias port is specified
|
var httpsPort = ((obj.args.aliasport == null) ? obj.args.port : obj.args.aliasport); // Use HTTPS alias port is specified
|
||||||
|
@ -719,10 +719,10 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
|
||||||
delete req.session.loginmode; // Clear this state, if the user hits refresh, we want to go back to the login page.
|
delete req.session.loginmode; // Clear this state, if the user hits refresh, we want to go back to the login page.
|
||||||
if ((parent.config != null) && (parent.config.settings != null) && (parent.config.settings.allowframing == true)) { features += 32; } // Allow site within iframe
|
if ((parent.config != null) && (parent.config.settings != null) && (parent.config.settings.allowframing == true)) { features += 32; } // Allow site within iframe
|
||||||
var httpsPort = ((obj.args.aliasport == null) ? obj.args.port : obj.args.aliasport); // Use HTTPS alias port is specified
|
var httpsPort = ((obj.args.aliasport == null) ? obj.args.port : obj.args.aliasport); // Use HTTPS alias port is specified
|
||||||
res.render(obj.path.join(__dirname, isModuleBrowser(req) ?'views/login-mobile':'views/login'), { loginmode: loginmode, rootCertLink: getRootCertLink(), title: domain.title, title2: domain.title2, newAccount: domain.newaccounts, newAccountPass: (((domain.newaccountspass == null) || (domain.newaccountspass == '')) ? 0 : 1), serverDnsName: getWebServerName(domain), serverPublicPort: httpsPort, emailcheck: obj.parent.mailserver != null, features: features, footer: (domain.footer == null) ? '' : domain.footer });
|
res.render(obj.path.join(__dirname, isModuleBrowser(req) ? 'views/login-mobile' : 'views/login'), { loginmode: loginmode, rootCertLink: getRootCertLink(), title: domain.title, title2: domain.title2, newAccount: domain.newaccounts, newAccountPass: (((domain.newaccountspass == null) || (domain.newaccountspass == '')) ? 0 : 1), serverDnsName: getWebServerName(domain), serverPublicPort: httpsPort, emailcheck: obj.parent.mailserver != null, features: features, footer: (domain.footer == null) ? '' : domain.footer });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the link to the root certificate if needed
|
// Get the link to the root certificate if needed
|
||||||
function getRootCertLink() {
|
function getRootCertLink() {
|
||||||
// TODO: This is not quite right, we need to check if the HTTPS certificate is issued from MeshCentralRoot, if so, add this download link.
|
// TODO: This is not quite right, we need to check if the HTTPS certificate is issued from MeshCentralRoot, if so, add this download link.
|
||||||
|
@ -738,9 +738,9 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
|
||||||
if (req.session && req.session.userid) {
|
if (req.session && req.session.userid) {
|
||||||
if (req.session.domainid != domain.id) { req.session.destroy(function () { res.redirect(domain.url); }); return; } // Check is the session is for the correct domain
|
if (req.session.domainid != domain.id) { req.session.destroy(function () { res.redirect(domain.url); }); return; } // Check is the session is for the correct domain
|
||||||
var user = obj.users[req.session.userid];
|
var user = obj.users[req.session.userid];
|
||||||
res.render(obj.path.join(__dirname, isModuleBrowser(req)?'views/terms-mobile':'views/terms'), { title: domain.title, title2: domain.title2, logoutControl: 'Welcome ' + user.name + '. <a href=' + domain.url + 'logout?' + Math.random() + ' style=color:white>Logout</a>' });
|
res.render(obj.path.join(__dirname, isModuleBrowser(req) ? 'views/terms-mobile' : 'views/terms'), { title: domain.title, title2: domain.title2, logoutControl: 'Welcome ' + user.name + '. <a href=' + domain.url + 'logout?' + Math.random() + ' style=color:white>Logout</a>' });
|
||||||
} else {
|
} else {
|
||||||
res.render(obj.path.join(__dirname, isModuleBrowser(req)?'views/terms-mobile':'views/terms'), { title: domain.title, title2: domain.title2 });
|
res.render(obj.path.join(__dirname, isModuleBrowser(req) ? 'views/terms-mobile' : 'views/terms'), { title: domain.title, title2: domain.title2 });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -771,7 +771,7 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
|
||||||
|
|
||||||
// Figure out the MPS port, use the alias if set
|
// Figure out the MPS port, use the alias if set
|
||||||
var mpsport = ((obj.args.mpsaliasport != null) ? obj.args.mpsaliasport : obj.args.mpsport);
|
var mpsport = ((obj.args.mpsaliasport != null) ? obj.args.mpsaliasport : obj.args.mpsport);
|
||||||
|
|
||||||
if ((serverNameSplit.length == 4) && (parseInt(serverNameSplit[0]) == serverNameSplit[0]) && (parseInt(serverNameSplit[1]) == serverNameSplit[1]) && (parseInt(serverNameSplit[2]) == serverNameSplit[2]) && (parseInt(serverNameSplit[3]) == serverNameSplit[3])) {
|
if ((serverNameSplit.length == 4) && (parseInt(serverNameSplit[0]) == serverNameSplit[0]) && (parseInt(serverNameSplit[1]) == serverNameSplit[1]) && (parseInt(serverNameSplit[2]) == serverNameSplit[2]) && (parseInt(serverNameSplit[3]) == serverNameSplit[3])) {
|
||||||
// Server name is an IPv4 address
|
// Server name is an IPv4 address
|
||||||
var filepath = obj.parent.path.join(__dirname, 'public/scripts/cira_setup_script_ip.mescript');
|
var filepath = obj.parent.path.join(__dirname, 'public/scripts/cira_setup_script_ip.mescript');
|
||||||
|
@ -837,7 +837,7 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle user public file downloads
|
// Handle user public file downloads
|
||||||
function handleDownloadUserFiles(req, res) {
|
function handleDownloadUserFiles(req, res) {
|
||||||
var domain = checkUserIpAddress(req, res);
|
var domain = checkUserIpAddress(req, res);
|
||||||
|
@ -847,7 +847,7 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
|
||||||
if (domain.id != '') { domainname = 'domain-' + domain.id; }
|
if (domain.id != '') { domainname = 'domain-' + domain.id; }
|
||||||
var path = obj.path.join(obj.filespath, domainname + "/user-" + spliturl[2] + "/Public");
|
var path = obj.path.join(obj.filespath, domainname + "/user-" + spliturl[2] + "/Public");
|
||||||
for (var i = 3; i < spliturl.length; i++) { if (obj.common.IsFilenameValid(spliturl[i]) == true) { path += '/' + spliturl[i]; filename = spliturl[i]; } else { res.sendStatus(404); return; } }
|
for (var i = 3; i < spliturl.length; i++) { if (obj.common.IsFilenameValid(spliturl[i]) == true) { path += '/' + spliturl[i]; filename = spliturl[i]; } else { res.sendStatus(404); return; } }
|
||||||
|
|
||||||
var stat = null;
|
var stat = null;
|
||||||
try { stat = obj.fs.statSync(path) } catch (e) { }
|
try { stat = obj.fs.statSync(path) } catch (e) { }
|
||||||
if ((stat != null) && ((stat.mode & 0x004000) == 0)) {
|
if ((stat != null) && ((stat.mode & 0x004000) == 0)) {
|
||||||
|
@ -855,7 +855,7 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
|
||||||
res.set({ 'Cache-Control': 'no-cache, no-store, must-revalidate', 'Pragma': 'no-cache', 'Expires': '0', 'Content-Type': 'application/octet-stream', 'Content-Disposition': 'attachment; filename=\"' + filename + '\"' });
|
res.set({ 'Cache-Control': 'no-cache, no-store, must-revalidate', 'Pragma': 'no-cache', 'Expires': '0', 'Content-Type': 'application/octet-stream', 'Content-Disposition': 'attachment; filename=\"' + filename + '\"' });
|
||||||
try { res.sendFile(obj.path.resolve(__dirname, path)); } catch (e) { res.sendStatus(404); }
|
try { res.sendFile(obj.path.resolve(__dirname, path)); } catch (e) { res.sendStatus(404); }
|
||||||
} else {
|
} else {
|
||||||
res.render(obj.path.join(__dirname, 'views/download'), { rootCertLink: getRootCertLink(), title: domain.title, title2: domain.title2, message: "<a href='" + req.path + "?download=1'>" + filename + "</a>, " + stat.size + " byte" + ((stat.size < 2)?'':'s') + "." });
|
res.render(obj.path.join(__dirname, 'views/download'), { rootCertLink: getRootCertLink(), title: domain.title, title2: domain.title2, message: "<a href='" + req.path + "?download=1'>" + filename + "</a>, " + stat.size + " byte" + ((stat.size < 2) ? '' : 's') + "." });
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
res.render(obj.path.join(__dirname, 'views/download'), { rootCertLink: getRootCertLink(), title: domain.title, title2: domain.title2, message: "Invalid file link, please check the URL again." });
|
res.render(obj.path.join(__dirname, 'views/download'), { rootCertLink: getRootCertLink(), title: domain.title, title2: domain.title2, message: "Invalid file link, please check the URL again." });
|
||||||
|
@ -863,7 +863,7 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
|
||||||
}
|
}
|
||||||
|
|
||||||
// Take a "user/domain/userid/path/file" format and return the actual server disk file path if access is allowed
|
// Take a "user/domain/userid/path/file" format and return the actual server disk file path if access is allowed
|
||||||
obj.getServerFilePath = function(user, domain, path) {
|
obj.getServerFilePath = function (user, domain, path) {
|
||||||
var splitpath = path.split('/'), serverpath = obj.path.join(obj.filespath, 'domain'), filename = '';
|
var splitpath = path.split('/'), serverpath = obj.path.join(obj.filespath, 'domain'), filename = '';
|
||||||
if ((splitpath.length < 3) || (splitpath[0] != 'user' && splitpath[0] != 'mesh') || (splitpath[1] != domain.id)) return null; // Basic validation
|
if ((splitpath.length < 3) || (splitpath[0] != 'user' && splitpath[0] != 'mesh') || (splitpath[1] != domain.id)) return null; // Basic validation
|
||||||
var objid = splitpath[0] + '/' + splitpath[1] + '/' + splitpath[2];
|
var objid = splitpath[0] + '/' + splitpath[1] + '/' + splitpath[2];
|
||||||
|
@ -877,7 +877,7 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return the maximum number of bytes allowed in the user account "My Files".
|
// Return the maximum number of bytes allowed in the user account "My Files".
|
||||||
obj.getQuota = function(objid, domain) {
|
obj.getQuota = function (objid, domain) {
|
||||||
if (objid == null) return 0;
|
if (objid == null) return 0;
|
||||||
if (objid.startsWith('user/')) {
|
if (objid.startsWith('user/')) {
|
||||||
var user = obj.users[objid];
|
var user = obj.users[objid];
|
||||||
|
@ -907,7 +907,7 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
|
||||||
res.set({ 'Cache-Control': 'no-cache, no-store, must-revalidate', 'Pragma': 'no-cache', 'Expires': '0', 'Content-Type': 'application/octet-stream', 'Content-Disposition': 'attachment; filename=\"' + file.name + '\"' });
|
res.set({ 'Cache-Control': 'no-cache, no-store, must-revalidate', 'Pragma': 'no-cache', 'Expires': '0', 'Content-Type': 'application/octet-stream', 'Content-Disposition': 'attachment; filename=\"' + file.name + '\"' });
|
||||||
try { res.sendFile(file.fullpath); } catch (e) { res.sendStatus(404); }
|
try { res.sendFile(file.fullpath); } catch (e) { res.sendStatus(404); }
|
||||||
}
|
}
|
||||||
|
|
||||||
// Upload a MeshCore.js file to the server
|
// Upload a MeshCore.js file to the server
|
||||||
function handleUploadMeshCoreFile(req, res) {
|
function handleUploadMeshCoreFile(req, res) {
|
||||||
var domain = checkUserIpAddress(req, res);
|
var domain = checkUserIpAddress(req, res);
|
||||||
|
@ -915,7 +915,7 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
|
||||||
if ((domain.id !== '') || (!req.session) || (req.session == null) || (!req.session.userid)) { res.sendStatus(401); return; }
|
if ((domain.id !== '') || (!req.session) || (req.session == null) || (!req.session.userid)) { res.sendStatus(401); return; }
|
||||||
var user = obj.users[req.session.userid];
|
var user = obj.users[req.session.userid];
|
||||||
if (user.siteadmin != 0xFFFFFFFF) { res.sendStatus(401); return; } // Check if we have mesh core upload rights (Full admin only)
|
if (user.siteadmin != 0xFFFFFFFF) { res.sendStatus(401); return; } // Check if we have mesh core upload rights (Full admin only)
|
||||||
|
|
||||||
var multiparty = require('multiparty');
|
var multiparty = require('multiparty');
|
||||||
var form = new multiparty.Form();
|
var form = new multiparty.Form();
|
||||||
form.parse(req, function (err, fields, files) {
|
form.parse(req, function (err, fields, files) {
|
||||||
|
@ -987,7 +987,7 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
|
||||||
res.send('');
|
res.send('');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Subscribe to all events we are allowed to receive
|
// Subscribe to all events we are allowed to receive
|
||||||
obj.subscribe = function (userid, target) {
|
obj.subscribe = function (userid, target) {
|
||||||
var user = obj.users[userid];
|
var user = obj.users[userid];
|
||||||
|
@ -1035,11 +1035,11 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
|
||||||
if (docs.length == 0) { console.log('ERR: Node not found'); return; }
|
if (docs.length == 0) { console.log('ERR: Node not found'); return; }
|
||||||
var node = docs[0];
|
var node = docs[0];
|
||||||
if (!node.intelamt) { console.log('ERR: Not AMT node'); return; }
|
if (!node.intelamt) { console.log('ERR: Not AMT node'); return; }
|
||||||
|
|
||||||
// Check if this user has permission to manage this computer
|
// Check if this user has permission to manage this computer
|
||||||
var meshlinks = user.links[node.meshid];
|
var meshlinks = user.links[node.meshid];
|
||||||
if ((!meshlinks) || (!meshlinks.rights) || ((meshlinks.rights & MESHRIGHT_REMOTECONTROL) == 0)) { console.log('ERR: Access denied (2)'); return; }
|
if ((!meshlinks) || (!meshlinks.rights) || ((meshlinks.rights & MESHRIGHT_REMOTECONTROL) == 0)) { console.log('ERR: Access denied (2)'); return; }
|
||||||
|
|
||||||
// Check what connectivity is available for this node
|
// Check what connectivity is available for this node
|
||||||
var state = parent.GetConnectivityState(req.query.host);
|
var state = parent.GetConnectivityState(req.query.host);
|
||||||
var conn = 0;
|
var conn = 0;
|
||||||
|
@ -1075,7 +1075,7 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
|
||||||
//if (node.intelamt.tls == 0) port = 16992; // DEBUG: Allow TLS flag to set TLS mode within CIRA
|
//if (node.intelamt.tls == 0) port = 16992; // DEBUG: Allow TLS flag to set TLS mode within CIRA
|
||||||
if (ciraconn.tag.boundPorts.indexOf(16992) >= 0) port = 16992; // RELEASE: Always use non-TLS mode if available within CIRA
|
if (ciraconn.tag.boundPorts.indexOf(16992) >= 0) port = 16992; // RELEASE: Always use non-TLS mode if available within CIRA
|
||||||
if (req.query.p == 2) port += 2;
|
if (req.query.p == 2) port += 2;
|
||||||
|
|
||||||
// Setup a new CIRA channel
|
// Setup a new CIRA channel
|
||||||
if ((port == 16993) || (port == 16995)) {
|
if ((port == 16993) || (port == 16995)) {
|
||||||
// Perform TLS - ( TODO: THIS IS BROKEN on Intel AMT v7 but works on v10, Not sure why )
|
// Perform TLS - ( TODO: THIS IS BROKEN on Intel AMT v7 but works on v10, Not sure why )
|
||||||
|
@ -1108,7 +1108,7 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
|
||||||
var tlsock = new TLSSocket(ser, tlsoptions);
|
var tlsock = new TLSSocket(ser, tlsoptions);
|
||||||
tlsock.on('error', function (err) { Debug(1, "CIRA TLS Connection Error ", err); });
|
tlsock.on('error', function (err) { Debug(1, "CIRA TLS Connection Error ", err); });
|
||||||
tlsock.on('secureConnect', function () { Debug(2, "CIRA Secure TLS Connection"); ws.resume(); });
|
tlsock.on('secureConnect', function () { Debug(2, "CIRA Secure TLS Connection"); ws.resume(); });
|
||||||
|
|
||||||
// Decrypted tunnel from TLS communcation to be forwarded to websocket
|
// Decrypted tunnel from TLS communcation to be forwarded to websocket
|
||||||
tlsock.on('data', function (data) {
|
tlsock.on('data', function (data) {
|
||||||
// AMT/TLS ---> WS
|
// AMT/TLS ---> WS
|
||||||
|
@ -1128,7 +1128,7 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
|
||||||
ws.forwardclient.xtls = 0;
|
ws.forwardclient.xtls = 0;
|
||||||
ws.resume();
|
ws.resume();
|
||||||
}
|
}
|
||||||
|
|
||||||
// When data is received from the web socket, forward the data into the associated CIRA cahnnel.
|
// When data is received from the web socket, forward the data into the associated CIRA cahnnel.
|
||||||
// If the CIRA connection is pending, the CIRA channel has built-in buffering, so we are ok sending anyway.
|
// If the CIRA connection is pending, the CIRA channel has built-in buffering, so we are ok sending anyway.
|
||||||
ws.on('message', function (msg) {
|
ws.on('message', function (msg) {
|
||||||
|
@ -1146,23 +1146,23 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
|
||||||
Debug(1, 'Websocket relay closed.');
|
Debug(1, 'Websocket relay closed.');
|
||||||
if (ws.forwardclient && ws.forwardclient.close) { ws.forwardclient.close(); } // TODO: If TLS is used, we need to close the socket that is wrapped by TLS
|
if (ws.forwardclient && ws.forwardclient.close) { ws.forwardclient.close(); } // TODO: If TLS is used, we need to close the socket that is wrapped by TLS
|
||||||
});
|
});
|
||||||
|
|
||||||
ws.forwardclient.onStateChange = function (ciraconn, state) {
|
ws.forwardclient.onStateChange = function (ciraconn, state) {
|
||||||
Debug(2, 'Relay CIRA state change', state);
|
Debug(2, 'Relay CIRA state change', state);
|
||||||
if (state == 0) { try { ws.close(); } catch (e) { } }
|
if (state == 0) { try { ws.close(); } catch (e) { } }
|
||||||
}
|
}
|
||||||
|
|
||||||
ws.forwardclient.onData = function (ciraconn, data) {
|
ws.forwardclient.onData = function (ciraconn, data) {
|
||||||
Debug(4, 'Relay CIRA data', data.length);
|
Debug(4, 'Relay CIRA data', data.length);
|
||||||
if (ws.interceptor) { data = ws.interceptor.processAmtData(data); } // Run data thru interceptor
|
if (ws.interceptor) { data = ws.interceptor.processAmtData(data); } // Run data thru interceptor
|
||||||
if (data.length > 0) { try { ws.send(data); } catch (e) { } } // TODO: Add TLS support
|
if (data.length > 0) { try { ws.send(data); } catch (e) { } } // TODO: Add TLS support
|
||||||
}
|
}
|
||||||
|
|
||||||
ws.forwardclient.onSendOk = function (ciraconn) {
|
ws.forwardclient.onSendOk = function (ciraconn) {
|
||||||
// TODO: Flow control? (Dont' really need it with AMT, but would be nice)
|
// TODO: Flow control? (Dont' really need it with AMT, but would be nice)
|
||||||
//console.log('onSendOk');
|
//console.log('onSendOk');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fetch Intel AMT credentials & Setup interceptor
|
// Fetch Intel AMT credentials & Setup interceptor
|
||||||
if (req.query.p == 1) {
|
if (req.query.p == 1) {
|
||||||
Debug(3, 'INTERCEPTOR1', { host: node.host, port: port, user: node.intelamt.user, pass: node.intelamt.pass });
|
Debug(3, 'INTERCEPTOR1', { host: node.host, port: port, user: node.intelamt.user, pass: node.intelamt.pass });
|
||||||
|
@ -1177,7 +1177,7 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If Intel AMT direct connection is possible, option a direct socket
|
// If Intel AMT direct connection is possible, option a direct socket
|
||||||
if ((conn & 4) != 0) { // We got a new web socket connection, initiate a TCP connection to the target Intel AMT host/port.
|
if ((conn & 4) != 0) { // We got a new web socket connection, initiate a TCP connection to the target Intel AMT host/port.
|
||||||
Debug(2, 'Opening relay TCP socket connection to ' + req.query.host + '.');
|
Debug(2, 'Opening relay TCP socket connection to ' + req.query.host + '.');
|
||||||
|
@ -1203,7 +1203,7 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
|
||||||
var port = 16992;
|
var port = 16992;
|
||||||
if (node.intelamt.tls > 0) port = 16993; // This is a direct connection, use TLS when possible
|
if (node.intelamt.tls > 0) port = 16993; // This is a direct connection, use TLS when possible
|
||||||
if (req.query.p == 2) port += 2;
|
if (req.query.p == 2) port += 2;
|
||||||
|
|
||||||
if (node.intelamt.tls == 0) {
|
if (node.intelamt.tls == 0) {
|
||||||
// If this is TCP (without TLS) set a normal TCP socket
|
// If this is TCP (without TLS) set a normal TCP socket
|
||||||
ws.forwardclient = new obj.net.Socket();
|
ws.forwardclient = new obj.net.Socket();
|
||||||
|
@ -1224,30 +1224,30 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
|
||||||
ws.forwardclient.xstate = 0;
|
ws.forwardclient.xstate = 0;
|
||||||
ws.forwardclient.forwardwsocket = ws;
|
ws.forwardclient.forwardwsocket = ws;
|
||||||
}
|
}
|
||||||
|
|
||||||
// When we receive data on the TCP connection, forward it back into the web socket connection.
|
// When we receive data on the TCP connection, forward it back into the web socket connection.
|
||||||
ws.forwardclient.on('data', function (data) {
|
ws.forwardclient.on('data', function (data) {
|
||||||
Debug(1, 'TCP relay data from ' + node.host + ', ' + data.length + ' bytes.'); // DEBUG
|
Debug(1, 'TCP relay data from ' + node.host + ', ' + data.length + ' bytes.'); // DEBUG
|
||||||
if (ws.interceptor) { data = ws.interceptor.processAmtData(data); } // Run data thru interceptor
|
if (ws.interceptor) { data = ws.interceptor.processAmtData(data); } // Run data thru interceptor
|
||||||
try { ws.send(new Buffer(data, 'binary')); } catch (e) { }
|
try { ws.send(new Buffer(data, 'binary')); } catch (e) { }
|
||||||
});
|
});
|
||||||
|
|
||||||
// If the TCP connection closes, disconnect the associated web socket.
|
// If the TCP connection closes, disconnect the associated web socket.
|
||||||
ws.forwardclient.on('close', function () {
|
ws.forwardclient.on('close', function () {
|
||||||
Debug(1, 'TCP relay disconnected from ' + node.host + '.');
|
Debug(1, 'TCP relay disconnected from ' + node.host + '.');
|
||||||
try { ws.close(); } catch (e) { }
|
try { ws.close(); } catch (e) { }
|
||||||
});
|
});
|
||||||
|
|
||||||
// If the TCP connection causes an error, disconnect the associated web socket.
|
// If the TCP connection causes an error, disconnect the associated web socket.
|
||||||
ws.forwardclient.on('error', function (err) {
|
ws.forwardclient.on('error', function (err) {
|
||||||
Debug(1, 'TCP relay error from ' + node.host + ': ' + err.errno);
|
Debug(1, 'TCP relay error from ' + node.host + ': ' + err.errno);
|
||||||
try { ws.close(); } catch (e) { }
|
try { ws.close(); } catch (e) { }
|
||||||
});
|
});
|
||||||
|
|
||||||
// Fetch Intel AMT credentials & Setup interceptor
|
// Fetch Intel AMT credentials & Setup interceptor
|
||||||
if (req.query.p == 1) { ws.interceptor = obj.interceptor.CreateHttpInterceptor({ host: node.host, port: port, user: node.intelamt.user, pass: node.intelamt.pass }); }
|
if (req.query.p == 1) { ws.interceptor = obj.interceptor.CreateHttpInterceptor({ host: node.host, port: port, user: node.intelamt.user, pass: node.intelamt.pass }); }
|
||||||
else if (req.query.p == 2) { ws.interceptor = obj.interceptor.CreateRedirInterceptor({ user: node.intelamt.user, pass: node.intelamt.pass }); }
|
else if (req.query.p == 2) { ws.interceptor = obj.interceptor.CreateRedirInterceptor({ user: node.intelamt.user, pass: node.intelamt.pass }); }
|
||||||
|
|
||||||
if (node.intelamt.tls == 0) {
|
if (node.intelamt.tls == 0) {
|
||||||
// A TCP connection to Intel AMT just connected, start forwarding.
|
// A TCP connection to Intel AMT just connected, start forwarding.
|
||||||
ws.forwardclient.connect(port, node.host, function () {
|
ws.forwardclient.connect(port, node.host, function () {
|
||||||
|
@ -1284,7 +1284,7 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
|
||||||
// If closed, do nothing
|
// If closed, do nothing
|
||||||
ws.on('close', function (req) { });
|
ws.on('close', function (req) { });
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the total size of all files in a folder and all sub-folders. (TODO: try to make all async version)
|
// Get the total size of all files in a folder and all sub-folders. (TODO: try to make all async version)
|
||||||
function readTotalFileSize(path) {
|
function readTotalFileSize(path) {
|
||||||
var r = 0, dir;
|
var r = 0, dir;
|
||||||
|
@ -1295,7 +1295,7 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
|
||||||
}
|
}
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete a folder and all sub items. (TODO: try to make all async version)
|
// Delete a folder and all sub items. (TODO: try to make all async version)
|
||||||
function deleteFolderRec(path) {
|
function deleteFolderRec(path) {
|
||||||
if (obj.fs.existsSync(path) == false) return;
|
if (obj.fs.existsSync(path) == false) return;
|
||||||
|
@ -1305,7 +1305,7 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
|
||||||
});
|
});
|
||||||
obj.fs.rmdirSync(path);
|
obj.fs.rmdirSync(path);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Handle Intel AMT events
|
// Handle Intel AMT events
|
||||||
// To subscribe, add "http://server:port/amtevents.ashx" to Intel AMT subscriptions.
|
// To subscribe, add "http://server:port/amtevents.ashx" to Intel AMT subscriptions.
|
||||||
obj.handleAmtEventRequest = function (req, res) {
|
obj.handleAmtEventRequest = function (req, res) {
|
||||||
|
@ -1316,29 +1316,29 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
|
||||||
if (authstr.substring(0, 7) == "Digest ") {
|
if (authstr.substring(0, 7) == "Digest ") {
|
||||||
var auth = obj.common.parseNameValueList(obj.common.quoteSplit(authstr.substring(7)));
|
var auth = obj.common.parseNameValueList(obj.common.quoteSplit(authstr.substring(7)));
|
||||||
if ((req.url === auth.uri) && (obj.httpAuthRealm === auth.realm) && (auth.opaque === obj.crypto.createHmac('SHA384', obj.httpAuthRandom).update(auth.nonce).digest('hex'))) {
|
if ((req.url === auth.uri) && (obj.httpAuthRealm === auth.realm) && (auth.opaque === obj.crypto.createHmac('SHA384', obj.httpAuthRandom).update(auth.nonce).digest('hex'))) {
|
||||||
|
|
||||||
// Read the data, we need to get the arg field
|
// Read the data, we need to get the arg field
|
||||||
var eventData = '';
|
var eventData = '';
|
||||||
req.on('data', function (chunk) { eventData += chunk; });
|
req.on('data', function (chunk) { eventData += chunk; });
|
||||||
req.on('end', function () {
|
req.on('end', function () {
|
||||||
|
|
||||||
// Completed event read, let get the argument that must contain the nodeid
|
// Completed event read, let get the argument that must contain the nodeid
|
||||||
var i = eventData.indexOf('<m:arg xmlns:m="http://x.com">');
|
var i = eventData.indexOf('<m:arg xmlns:m="http://x.com">');
|
||||||
if (i > 0) {
|
if (i > 0) {
|
||||||
var nodeid = eventData.substring(i + 30, i + 30 + 64);
|
var nodeid = eventData.substring(i + 30, i + 30 + 64);
|
||||||
if (nodeid.length == 64) {
|
if (nodeid.length == 64) {
|
||||||
var nodekey = 'node/' + domain.id + '/' + nodeid;
|
var nodekey = 'node/' + domain.id + '/' + nodeid;
|
||||||
|
|
||||||
// See if this node exists in the database
|
// See if this node exists in the database
|
||||||
obj.db.Get(nodekey, function (err, nodes) {
|
obj.db.Get(nodekey, function (err, nodes) {
|
||||||
if (nodes.length == 1) {
|
if (nodes.length == 1) {
|
||||||
// Yes, the node exists, compute Intel AMT digest password
|
// Yes, the node exists, compute Intel AMT digest password
|
||||||
var node = nodes[0];
|
var node = nodes[0];
|
||||||
var amtpass = obj.crypto.createHash('sha384').update(auth.username.toLowerCase() + ":" + nodeid + ":" + obj.parent.dbconfig.amtWsEventSecret).digest("base64").substring(0, 12).split("/").join("x").split("\\").join("x");
|
var amtpass = obj.crypto.createHash('sha384').update(auth.username.toLowerCase() + ":" + nodeid + ":" + obj.parent.dbconfig.amtWsEventSecret).digest("base64").substring(0, 12).split("/").join("x").split("\\").join("x");
|
||||||
|
|
||||||
// Check the MD5 hash
|
// Check the MD5 hash
|
||||||
if (auth.response === obj.common.ComputeDigesthash(auth.username, amtpass, auth.realm, "POST", auth.uri, auth.qop, auth.nonce, auth.nc, auth.cnonce)) {
|
if (auth.response === obj.common.ComputeDigesthash(auth.username, amtpass, auth.realm, "POST", auth.uri, auth.qop, auth.nonce, auth.nc, auth.cnonce)) {
|
||||||
|
|
||||||
// This is an authenticated Intel AMT event, update the host address
|
// This is an authenticated Intel AMT event, update the host address
|
||||||
var amthost = req.connection.remoteAddress;
|
var amthost = req.connection.remoteAddress;
|
||||||
if (amthost.substring(0, 7) === '::ffff:') { amthost = amthost.substring(7); }
|
if (amthost.substring(0, 7) === '::ffff:') { amthost = amthost.substring(7); }
|
||||||
|
@ -1359,10 +1359,10 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
|
||||||
obj.parent.DispatchEvent(['*', node.meshid], obj, event);
|
obj.parent.DispatchEvent(['*', node.meshid], obj, event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
parent.amtEventHandler.handleAmtEvent(eventData, nodeid, amthost);
|
parent.amtEventHandler.handleAmtEvent(eventData, nodeid, amthost);
|
||||||
//res.send('OK');
|
//res.send('OK');
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1374,7 +1374,7 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (e) { console.log(e); }
|
} catch (e) { console.log(e); }
|
||||||
|
|
||||||
// Send authentication response
|
// Send authentication response
|
||||||
obj.crypto.randomBytes(48, function (err, buf) {
|
obj.crypto.randomBytes(48, function (err, buf) {
|
||||||
var nonce = buf.toString('hex'), opaque = obj.crypto.createHmac('SHA384', obj.httpAuthRandom).update(nonce).digest('hex');
|
var nonce = buf.toString('hex'), opaque = obj.crypto.createHmac('SHA384', obj.httpAuthRandom).update(nonce).digest('hex');
|
||||||
|
@ -1382,7 +1382,7 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
|
||||||
res.sendStatus(401);
|
res.sendStatus(401);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle a server backup request
|
// Handle a server backup request
|
||||||
function handleBackupRequest(req, res) {
|
function handleBackupRequest(req, res) {
|
||||||
var domain = checkUserIpAddress(req, res);
|
var domain = checkUserIpAddress(req, res);
|
||||||
|
@ -1394,16 +1394,16 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
|
||||||
// Require modules
|
// Require modules
|
||||||
var fs = require('fs');
|
var fs = require('fs');
|
||||||
var archive = require('archiver')('zip', { level: 9 }); // Sets the compression method to maximum.
|
var archive = require('archiver')('zip', { level: 9 }); // Sets the compression method to maximum.
|
||||||
|
|
||||||
// Good practice to catch this error explicitly
|
// Good practice to catch this error explicitly
|
||||||
archive.on('error', function (err) { throw err; });
|
archive.on('error', function (err) { throw err; });
|
||||||
|
|
||||||
// Set the archive name
|
// Set the archive name
|
||||||
res.attachment(domain.title + '-Backup-' + new Date().toLocaleDateString().replace('/', '-').replace('/', '-') + '.zip');
|
res.attachment(domain.title + '-Backup-' + new Date().toLocaleDateString().replace('/', '-').replace('/', '-') + '.zip');
|
||||||
|
|
||||||
// Pipe archive data to the file
|
// Pipe archive data to the file
|
||||||
archive.pipe(res);
|
archive.pipe(res);
|
||||||
|
|
||||||
// Append all of the files for this backup
|
// Append all of the files for this backup
|
||||||
var backupList = ['config.json', 'meshcentral.db', 'agentserver-cert-private.key', 'agentserver-cert-public.crt', 'mpsserver-cert-private.key', 'mpsserver-cert-public.crt', 'data/root-cert-private.key', 'root-cert-public.crt', 'webserver-cert-private.key', 'webserver-cert-public.crt'];
|
var backupList = ['config.json', 'meshcentral.db', 'agentserver-cert-private.key', 'agentserver-cert-public.crt', 'mpsserver-cert-private.key', 'mpsserver-cert-public.crt', 'data/root-cert-private.key', 'root-cert-public.crt', 'webserver-cert-private.key', 'webserver-cert-public.crt'];
|
||||||
for (var i in backupList) {
|
for (var i in backupList) {
|
||||||
|
@ -1415,7 +1415,7 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
|
||||||
// Finalize the archive (ie we are done appending files but streams have to finish yet)
|
// Finalize the archive (ie we are done appending files but streams have to finish yet)
|
||||||
archive.finalize();
|
archive.finalize();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle a server restore request
|
// Handle a server restore request
|
||||||
function handleRestoreRequest(req, res) {
|
function handleRestoreRequest(req, res) {
|
||||||
var domain = checkUserIpAddress(req, res);
|
var domain = checkUserIpAddress(req, res);
|
||||||
|
@ -1423,7 +1423,7 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
|
||||||
if ((domain.id !== '') || (!req.session) || (req.session == null) || (!req.session.userid) || (obj.parent.args.noserverbackup == 1)) { res.sendStatus(401); return; }
|
if ((domain.id !== '') || (!req.session) || (req.session == null) || (!req.session.userid) || (obj.parent.args.noserverbackup == 1)) { res.sendStatus(401); return; }
|
||||||
var user = obj.users[req.session.userid];
|
var user = obj.users[req.session.userid];
|
||||||
if ((user.siteadmin & 4) == 0) { res.sendStatus(401); return; } // Check if we have server restore rights
|
if ((user.siteadmin & 4) == 0) { res.sendStatus(401); return; } // Check if we have server restore rights
|
||||||
|
|
||||||
var multiparty = require('multiparty');
|
var multiparty = require('multiparty');
|
||||||
var form = new multiparty.Form();
|
var form = new multiparty.Form();
|
||||||
form.parse(req, function (err, fields, files) {
|
form.parse(req, function (err, fields, files) {
|
||||||
|
@ -1431,7 +1431,7 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
|
||||||
parent.Stop(files.datafile[0].path);
|
parent.Stop(files.datafile[0].path);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle a request to download a mesh agent
|
// Handle a request to download a mesh agent
|
||||||
obj.handleMeshAgentRequest = function (req, res) {
|
obj.handleMeshAgentRequest = function (req, res) {
|
||||||
var domain = checkUserIpAddress(req, res);
|
var domain = checkUserIpAddress(req, res);
|
||||||
|
@ -1646,7 +1646,7 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
|
||||||
// Setup all HTTP handlers
|
// Setup all HTTP handlers
|
||||||
obj.app.get('/backup.zip', handleBackupRequest);
|
obj.app.get('/backup.zip', handleBackupRequest);
|
||||||
obj.app.post('/restoreserver.ashx', handleRestoreRequest);
|
obj.app.post('/restoreserver.ashx', handleRestoreRequest);
|
||||||
if (parent.multiServer != null) { obj.app.ws('/meshserver.ashx', function (ws, req) { parent.multiServer.CreatePeerInServer(parent.multiServer, ws, req); } ); }
|
if (parent.multiServer != null) { obj.app.ws('/meshserver.ashx', function (ws, req) { parent.multiServer.CreatePeerInServer(parent.multiServer, ws, req); }); }
|
||||||
for (var i in parent.config.domains) {
|
for (var i in parent.config.domains) {
|
||||||
if (parent.config.domains[i].dns != null) { continue; } // This is a subdomain with a DNS name, no added HTTP bindings needed.
|
if (parent.config.domains[i].dns != null) { continue; } // This is a subdomain with a DNS name, no added HTTP bindings needed.
|
||||||
var url = parent.config.domains[i].url;
|
var url = parent.config.domains[i].url;
|
||||||
|
@ -1713,7 +1713,7 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
|
||||||
}
|
}
|
||||||
|
|
||||||
// Force mesh agent disconnection
|
// Force mesh agent disconnection
|
||||||
obj.forceMeshAgentDisconnect = function(user, domain, nodeid, disconnectMode) {
|
obj.forceMeshAgentDisconnect = function (user, domain, nodeid, disconnectMode) {
|
||||||
if (nodeid == null) return;
|
if (nodeid == null) return;
|
||||||
var splitnode = nodeid.split('/');
|
var splitnode = nodeid.split('/');
|
||||||
if ((splitnode.length != 3) || (splitnode[1] != domain.id)) return; // Check that nodeid is valid and part of our domain
|
if ((splitnode.length != 3) || (splitnode[1] != domain.id)) return; // Check that nodeid is valid and part of our domain
|
||||||
|
@ -1726,7 +1726,7 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send the core module to the mesh agent
|
// Send the core module to the mesh agent
|
||||||
obj.sendMeshAgentCore = function(user, domain, nodeid, core) {
|
obj.sendMeshAgentCore = function (user, domain, nodeid, core) {
|
||||||
if (nodeid == null) return;
|
if (nodeid == null) return;
|
||||||
var splitnode = nodeid.split('/');
|
var splitnode = nodeid.split('/');
|
||||||
if ((splitnode.length != 3) || (splitnode[1] != domain.id)) return; // Check that nodeid is valid and part of our domain
|
if ((splitnode.length != 3) || (splitnode[1] != domain.id)) return; // Check that nodeid is valid and part of our domain
|
||||||
|
@ -1754,7 +1754,7 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the server path of a user or mesh object
|
// Get the server path of a user or mesh object
|
||||||
function getServerRootFilePath(obj) {
|
function getServerRootFilePath(obj) {
|
||||||
if ((typeof obj != 'object') || (obj.domain == null) || (obj._id == null)) return null;
|
if ((typeof obj != 'object') || (obj.domain == null) || (obj._id == null)) return null;
|
||||||
|
@ -1763,7 +1763,7 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
|
||||||
if (obj.domain !== '') domainname = 'domain-' + obj.domain;
|
if (obj.domain !== '') domainname = 'domain-' + obj.domain;
|
||||||
return obj.path.join(obj.filespath, domainname + "/" + splitname[0] + "-" + splitname[2]);
|
return obj.path.join(obj.filespath, domainname + "/" + splitname[0] + "-" + splitname[2]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read entire file and return it in callback function
|
// Read entire file and return it in callback function
|
||||||
function readEntireTextFile(filepath, func) {
|
function readEntireTextFile(filepath, func) {
|
||||||
var called = false;
|
var called = false;
|
||||||
|
@ -1806,13 +1806,13 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
|
||||||
// Start server on a free port
|
// Start server on a free port
|
||||||
CheckListenPort(obj.args.port, StartWebServer);
|
CheckListenPort(obj.args.port, StartWebServer);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
obj.wssessions = {}; // UserId --> Array Of Sessions
|
obj.wssessions = {}; // UserId --> Array Of Sessions
|
||||||
obj.wssessions2 = {}; // "UserId + SessionRnd" --> Session (Note that the SessionId is the UserId + / + SessionRnd)
|
obj.wssessions2 = {}; // "UserId + SessionRnd" --> Session (Note that the SessionId is the UserId + / + SessionRnd)
|
||||||
obj.wsPeerSessions = {}; // ServerId --> Array Of "UserId + SessionRnd"
|
obj.wsPeerSessions = {}; // ServerId --> Array Of "UserId + SessionRnd"
|
||||||
obj.wsPeerSessions2 = {}; // "UserId + SessionRnd" --> ServerId
|
obj.wsPeerSessions2 = {}; // "UserId + SessionRnd" --> ServerId
|
||||||
obj.wsPeerSessions3 = {}; // ServerId --> UserId --> [ SessionId ]
|
obj.wsPeerSessions3 = {}; // ServerId --> UserId --> [ SessionId ]
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Count sessions and event any changes
|
// Count sessions and event any changes
|
||||||
obj.recountSessions = function (changedSessionId) {
|
obj.recountSessions = function (changedSessionId) {
|
||||||
|
@ -1872,10 +1872,10 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return true if a mobile browser is detected.
|
// Return true if a mobile browser is detected.
|
||||||
// This code comes from "http://detectmobilebrowsers.com/", This is free and unencumbered software released into the public domain. For more information, please refer to the http://unlicense.org/
|
// This code comes from "http://detectmobilebrowsers.com/" and was modified, This is free and unencumbered software released into the public domain. For more information, please refer to the http://unlicense.org/
|
||||||
function isModuleBrowser(req) {
|
function isModuleBrowser(req) {
|
||||||
var ua = req.headers['user-agent'].toLowerCase();
|
var ua = req.headers['user-agent'].toLowerCase();
|
||||||
return (/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test(ua) || /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(ua.substr(0, 4)));
|
return (/(android|bb\d+|meego).+mobile|mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test(ua) || /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(ua.substr(0, 4)));
|
||||||
}
|
}
|
||||||
|
|
||||||
return obj;
|
return obj;
|
||||||
|
|
Loading…
Reference in a new issue