mirror of
https://github.com/Ylianst/MeshCentral.git
synced 2024-12-24 06:05:53 -05:00
Improved Windows agent crash logs and mobile phone login page
This commit is contained in:
parent
328a6ff4d6
commit
098841fdc1
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 New Issue
Block a user