/**
* @file outlook_web_access.js
* @desc
* Looks for Outlook signatures in html data.
* To get a good set of test web sites -
* google search keywords -
* 1. intitle:"Microsoft Outlook Web Access"
* 2. inurl:"/owa/auth/logon.aspx?url="
*
* Additional signature related info are available at -
* 1. https://goo.gl/IPG41D
* 2. Chrome plugin 'wappalyzer' src.
*
* The signature info are outdated and may not be valid for Outlook 2013.
* Other notes and sample web sites -
*
* 1. Outlook 2003 -
* Microsoft internal version number - 6.5.X
* Useful Http response headers -
* X-Powered-By:ASP.NET
*
* Useful html signature elements -
* <!-- {57A118C6-2DA9-419d-BE9A-F92B0F9A418B} -->
* <TITLE>Microsoft Outlook Web Access</TITLE>
* <FORM action="/exchweb/bin/auth/owaauth.dll" method="POST" name="logonForm">
*
* Sample website -
* https://mailhost.wcl.american.edu/
* https://goo.gl/FlNI0x
* https://goo.gl/RIeumA
*
* 2. Outlook 2007 -
* Microsoft internal version number - 8.X
* Useful Http response headers -
* X-OWA-Version:8.3.379.2
* X-Powered-By:ASP.NET
*
* Useful html signature elements -
* <!-- OwaPage = ASP.auth_logon_aspx -->
* <!-- {57A118C6-2DA9-419d-BE9A-F92B0F9A418B} -->
* <title>Microsoft Exchange - Outlook Web Access</title>
* <link type="text/css" rel="stylesheet"
* href="/owa/8.3.379.2/themes/base/logon.css">
* <link type="text/css" rel="stylesheet"
* href="/owa/8.3.379.2/themes/base/owafont.css">
* <form action="owaauth.dll" method="POST" name="logonForm"
* autocomplete="off" id="loginform">
*
* Sample website -
* https://goo.gl/OAVu1V
*
* 3. Outlook 2010 -
* Microsoft internal version number - 14.X
* Useful Http response headers -
* X-OWA-Version:14.3.195.1
* X-Powered-By:ASP.NET
*
* Useful html signature elements -
* <!-- OwaPage = ASP.auth_logon_aspx -->
* <!-- {57A118C6-2DA9-419d-BE9A-F92B0F9A418B} -->
* <title>Outlook Web App</title>
* <link rel="shortcut icon" href="/owa/14.3.195.1/themes/resources/favicon.ico"
* type="image/x-icon">
* <link type="text/css" rel="stylesheet"
* href="/owa/14.3.195.1/themes/resources/logon.css">
* <link type="text/css" rel="stylesheet"
* href="/owa/14.3.195.1/themes/resources/owafont.css">
* <form action="/owa/auth.owa" method="POST" name="logonForm">
*
* Sample website -
* https://outlook.leeds.ac.uk/owa/auth/logon.aspx?replaceCurrent=1
* https://goo.gl/jVo6rv
* https://goo.gl/Qr7IWa
*
* 4. Outlook 2013 -
* Microsoft internal version number - 15.X
* Useful Http response headers -
* Server:Microsoft-IIS/8.5
* X-AspNet-Version:4.0.30319
* X-Powered-By:ASP.NET
*
* Useful html signature elements -
* <!-- OwaPage = ASP.auth_logon_aspx -->
* <!-- {57A118C6-2DA9-419d-BE9A-F92B0F9A418B} -->
* <link rel="shortcut icon" href="/owa/auth/15.0.1044/themes/resources/favicon.ico"
* type="image/x-icon">
* <title>Outlook Web App</title>
*
* Sample website -
* https://goo.gl/Zp6zIf
*
* Some special OWA pages which do not match the above criteria -
* 1. https://owa.marriott.com/CookieAuth.dll?GetLogon?curl=Z2Fowa&reason=0&formdir=1
*
* Finger-printing works in this case. But, we are not sure about the version
*
* 2. https://email.tsa.dhs.gov/my.policy
* Finger-printing does not work in this case. It uses a heavily customized
* Outlook 2010.
*/
'use strict';
var _ = require('lodash'),
domutils = require('domutils'),
logger = require(__dirname + '/../loggers/logger');
var owaTitles = ['Microsoft Outlook Web Access', //outlook 2003
'Microsoft Exchange - Outlook Web Access', //outlook 2007
'Outlook Web Access', //outlook 2007
'Outlook Web App'], //outlook 2010/2013
owaFormActions = ['/exchweb/bin/auth/owaauth.dll', //outlook 2003
'owaauth.dll', //outlook 2007
'/owa/auth.owa', //outlook 2010
'/cookieauth.dll?logon'], //probably 2010
owaComments = ['OwaPage = ASP.auth_logon_aspx', //outlook 2007/10/13
'{57A118C6-2DA9-419d-BE9A-F92B0F9A418B}'];//outlook 2007/10/13
var owaIconRegExes = [
// outlook 2010
new RegExp('\/owa\/([^\s^\/]+)\/themes\/resources\/favicon\.ico'),
// outlook 2013
new RegExp('\/owa\/auth\/([^\s^\/]+)\/themes\/resources\/favicon\.ico')],
owaCssRegExes = [
// outlook 2010
new RegExp('\/owa\/([^\s^\/]+)\/themes\/resources\/logon\.css'),
new RegExp('\/owa\/([^\s^\/]+)\/themes\/resources\/owafont\.css'),
// outlook 2007
new RegExp('\/owa\/([^\s^\/]+)\/themes\/base\/logon\.css'),
new RegExp('\/owa\/([^\s^\/]+)\/themes\/base\/owafont\.css')];
var getValue = function (obj, property) {
return _.isUndefined(obj[property]) ? '' : obj[property];
};
var analyzer = function () {
var isEnabled = true,
owaServerName = '',
owaServerVersion = '';
this.init = function (headers) {
if (!headers || !headers.url) {
return;
}
var xOwaHeader = getValue(headers, 'x-owa-version');
if (xOwaHeader) {
// If we find a header like 'X-OWA-Version:14.3.195.1'
// We don't need to parse the html at all. We can be
// sure that it is a OWA server.
owaServerName = 'Outlook Web Access';
owaServerVersion = xOwaHeader.replace(/[^\d.]/g, '');
logger.info('xOwaHeader found - ' + owaServerName);
isEnabled = false;
return;
}
};
this.isEnabledForDomWatch = function () {
return isEnabled;
};
this.getServerInfo = function () {
var serverInfos = [];
if (owaServerName) {
var serverInfo = {};
serverInfo.name = owaServerName;
serverInfo.version = owaServerVersion;
serverInfos.push(serverInfo);
}
return serverInfos;
};
this.inspectCommentNode = function (element) {
if (!element.data) {
return;
}
// Some OWA pages have the following comment at the very top of page.
//<!-- OwaPage = ASP.auth_logon_aspx -->
var comment = element.data;
_.some(owaComments, function (owaComment) {
if (comment.indexOf(owaComment) > -1) {
owaServerName = 'Outlook Web Access';
logger.info('OWA: comment match - ' + comment);
return true; // stop looping
}
});
};
this.inspectTitle = function (element) {
var text = domutils.getText(element);
_.some(owaTitles, function (owaTitle) {
if (text.indexOf(owaTitle) > -1) {
owaServerName = 'Outlook Web Access';
logger.info('OWA: Page title match - ' + text);
return true; // stop looping
}
});
};
this.inspectForm = function (element) {
// OWA form action is of the following pattern -
//<FORM action="/exchweb/bin/auth/owaauth.dll" name="logonForm">
//<form action="/owa/auth.owa" method="POST" name="logonForm">
var formAction = domutils.getAttributeValue(element, 'action');
if (!formAction) {
return;
}
formAction = formAction.toLowerCase();
_.some(owaFormActions, function (owaFormAction) {
if (formAction.indexOf(owaFormAction) > -1) {
owaServerName = 'Outlook Web Access';
logger.info('OWA: Form action match - ' + formAction);
return true; // stop looping
}
});
};
this.matchRegExes = function (href, regExes) {
var matchVal = null;
_.some(regExes, function (reg) {
matchVal = href.match(reg);
return matchVal;
});
if (matchVal && matchVal.length === 2) {
owaServerName = 'Outlook Web Access';
owaServerVersion = matchVal[1];
isEnabled = false; // No more dom watch required.
logger.info('OWA: Found regex match, OWA Version - ' + matchVal[1]);
}
};
this.inspectLink = function (element) {
var rel = domutils.getAttributeValue(element, 'rel'),
href = domutils.getAttributeValue(element, 'href'),
type = domutils.getAttributeValue(element, 'type');
if (!rel || !href || !type) {
return;
}
if ((rel === 'shortcut icon') && (type === 'image/x-icon')) {
// OWA pages usually have a shortcut icon in the following pattern -
// <link rel="shortcut icon" type="image/x-icon"
// href="/owa/14.3.195.1/themes/resources/favicon.ico">
this.matchRegExes(href, owaIconRegExes);
return;
}
if ((rel === 'stylesheet') && (type === 'text/css')) {
// OWA pages usually have a stylesheets in the following pattern -
// <link rel="stylesheet" type="text/css"
// href="/owa/14.3.195.1/themes/resources/logon.css">
this.matchRegExes(href, owaCssRegExes);
}
};
this.inspectDomNode = function (element) {
if (!isEnabled){
return;
}
if(!domutils.isTag(element) && (element.type === 'comment')) {
this.inspectCommentNode(element);
return;
}
switch (element.name)
{
case 'title':
this.inspectTitle(element);
break;
case 'form':
this.inspectForm(element);
break;
case 'link':
this.inspectLink(element);
break;
}
};
};
module.exports = analyzer;
|