diff --git a/lib/platformUtils/windows10Utils.js b/lib/platformUtils/windows10Utils.js
index b44d48ae..59de5b61 100644
--- a/lib/platformUtils/windows10Utils.js
+++ b/lib/platformUtils/windows10Utils.js
@@ -14,6 +14,46 @@ var metadataItemTemplate= '\r\n\t\t';
var serviceEndpoint = 'http://cloudappx.azurewebsites.net';
+var baseAcurMatch;
+
+function findRuleByMatch(acurList, match) {
+ for (var i = 0; i < acurList.length; i++) {
+ if (acurList[i].match === match) {
+ return acurList[i];
+ }
+ }
+}
+
+function tryAddAcurToList(acurList, acur) {
+ // if match is '*', replace match with base match
+ if (acur.match === '*') {
+ acur.match = baseAcurMatch;
+ }
+
+ // if the match url ends with '/*', remove the '*'.
+ if (acur.match.indexOf('/*', acur.match.length - 2) !== -1) {
+ acur.match = acur.match.substring(0, acur.match.length - 1);
+ }
+
+ // ensure rule is not duplicated
+ var rule = findRuleByMatch(acurList, acur.match);
+ if (!rule) {
+ // if no type is specified in rule and access is 'none', ignore the rule
+ if (!acur.type && acur.runtimeAccess === 'none') {
+ return;
+ }
+
+ rule = { match: acur.match };
+ acurList.push(rule);
+ }
+
+ // override the runtimeAccess property (if any) or use default value ('none')
+ rule.runtimeAccess = acur.runtimeAccess || rule.runtimeAccess || 'none';
+
+ // override the type (if any) or use default value ('include')
+ rule.type = acur.type || rule.type || 'include';
+}
+
function replaceManifestValues(w3cManifestInfo, content) {
var w3cManifest = w3cManifestInfo.content;
var timestamp = w3cManifestInfo.timestamp || new Date().toISOString().replace(/T/, ' ').replace(/\.[0-9]+/, ' ');
@@ -45,54 +85,54 @@ function replaceManifestValues(w3cManifestInfo, content) {
replacedContent = replacedContent.replace(/{MetadataItems}/g, metadataItems);
- // Update access rules
+ // Update ACURs
var indentationChars = '\r\n\t\t\t\t';
+ var applicationContentUriRules = '';
+ var acurList = [];
- // Set the base access rule using the start_url's base url
- var baseUrlPattern = url.resolve(w3cManifest.start_url, '/');
- var baseApiAccess = 'none';
+ // Set the base acur rule using the start_url's base url
+ baseAcurMatch = url.resolve(w3cManifest.start_url, '/');
if (w3cManifest.scope && w3cManifest.scope.length) {
// If the scope is defined, the base access rule is defined by the scope
var parsedScopeUrl = url.parse(w3cManifest.scope);
if (parsedScopeUrl.host && parsedScopeUrl.protocol) {
- baseUrlPattern = w3cManifest.scope;
+ baseAcurMatch = w3cManifest.scope;
} else {
- baseUrlPattern = url.resolve(baseUrlPattern, w3cManifest.scope);
+ baseAcurMatch = url.resolve(baseAcurMatch, w3cManifest.scope);
}
}
- // If the base access rule ends with '/*', remove the '*'.
- if (baseUrlPattern.indexOf('/*', baseUrlPattern.length - 2) !== -1) {
- baseUrlPattern = baseUrlPattern.substring(0, baseUrlPattern.length - 1);
- }
+ // Add base rule to ACUR list
+ tryAddAcurToList(acurList, { 'match': baseAcurMatch, 'type': 'include' });
- var applicationContentUriRules = '';
-
- // Add additional access rules
- if (w3cManifest.mjs_access_whitelist && w3cManifest.mjs_access_whitelist instanceof Array) {
- for (var j = 0; j < w3cManifest.mjs_access_whitelist.length; j++) {
- var accessUrl = w3cManifest.mjs_access_whitelist[j].url;
- // Ignore the '*' rule
- if (accessUrl !== '*') {
- // If the access url ends with '/*', remove the '*'.
- if (accessUrl.indexOf('/*', accessUrl.length - 2) !== -1) {
- accessUrl = accessUrl.substring(0, accessUrl.length - 1);
- }
-
- var apiAccess = w3cManifest.mjs_access_whitelist[j].apiAccess || 'none';
-
- if (accessUrl === baseUrlPattern) {
- baseApiAccess = apiAccess;
- } else {
- applicationContentUriRules += indentationChars + '';
- }
- }
- }
+ // Add rules from mjs_access_whitelist to ACUR list
+ if (w3cManifest.mjs_access_whitelist) {
+ w3cManifest.mjs_access_whitelist.forEach(function(whitelistRule) {
+ tryAddAcurToList(acurList, { 'match': whitelistRule.url, 'type': 'include', 'runtimeAccess': whitelistRule.apiAccess });
+ });
}
+
+ // TODO: Add rules from mjs_extended_scope to ACUR list
+
+ // Add rules from mjs_api_access to ACUR list
+ if (w3cManifest.mjs_api_access) {
+ w3cManifest.mjs_api_access.forEach(function (apiRule) {
+ // ensure rule applies to current platform
+ if (apiRule.platform && apiRule.platform.split(';')
+ .map(function (item) { return item.trim(); })
+ .indexOf('windows10') < 0) {
+ return false;
+ }
+
+ tryAddAcurToList(acurList, { match: apiRule.match, runtimeAccess: apiRule.access });
+ });
+ }
- // Added base rule
- applicationContentUriRules = '' + applicationContentUriRules;
+ // Create XML entries for ACUR rules
+ acurList.forEach(function (acur) {
+ applicationContentUriRules += indentationChars + '';
+ });
replacedContent = replacedContent.replace(/{ApplicationContentUriRules}/g, applicationContentUriRules);
diff --git a/test/manifestTools/transformations/windows10.js b/test/manifestTools/transformations/windows10.js
index a4c69d34..cd2701b0 100644
--- a/test/manifestTools/transformations/windows10.js
+++ b/test/manifestTools/transformations/windows10.js
@@ -383,7 +383,7 @@ describe('transformation: Windows 10 Manifest', function () {
});
});
- it('Should enable API access in base rule', function (done) {
+ it('Should use mjs_access_whitelist to enable API access in base ACUR', function (done) {
var siteUrl = 'http://url.com/something?query';
var shortName = 'shortName';
@@ -418,7 +418,7 @@ describe('transformation: Windows 10 Manifest', function () {
});
});
- it('Should enable API in secondary rule but not in base rule', function (done) {
+ it('Should use mjs_access_whitelist to enable API access in secondary ACUR but not in base ACUR', function (done) {
var siteUrl = 'http://url.com/something?query';
var shortName = 'shortName';
@@ -453,5 +453,261 @@ describe('transformation: Windows 10 Manifest', function () {
done();
});
});
+
+ it('Should use mjs_api_access to enable API access in base ACUR', function (done) {
+ var siteUrl = 'http://url.com/something?query';
+ var shortName = 'shortName';
+
+ var originalManifestInfo = {
+ content: {
+ 'start_url': siteUrl,
+ 'short_name': shortName,
+ 'mjs_api_access': [
+ { 'match': 'http://url.com/', 'access': 'all' }
+ ]
+ }
+ };
+
+ transformation.convertFromBase(originalManifestInfo, function (err, result) {
+ should.not.exist(err);
+ should.exist(result);
+ /*jshint -W030 */
+ result.should.have.property('content').which.is.an.Object;
+ result.should.have.property('format', 'windows10');
+
+ var manifest = result.content;
+
+ manifest.should.have.property('rawData');
+
+ var expectedContentUriRules = '' +
+ '' +
+ '';
+
+ manifest.rawData.replace(/[\t\r\n]/g, '').indexOf(expectedContentUriRules).should.be.above(-1);
+
+ done();
+ });
+ });
+
+ it('Should use mjs_api_access to enable API access in secondary ACUR but not in base ACUR', function (done) {
+ var siteUrl = 'http://url.com/something?query';
+ var shortName = 'shortName';
+
+ var originalManifestInfo = {
+ content: {
+ 'start_url': siteUrl,
+ 'short_name': shortName,
+ 'mjs_api_access': [
+ { 'match': 'http://url.com/somepath/', 'access': 'all' }
+ ]
+ }
+ };
+
+ transformation.convertFromBase(originalManifestInfo, function (err, result) {
+ should.not.exist(err);
+ should.exist(result);
+ /*jshint -W030 */
+ result.should.have.property('content').which.is.an.Object;
+ result.should.have.property('format', 'windows10');
+
+ var manifest = result.content;
+
+ manifest.should.have.property('rawData');
+
+ var expectedContentUriRules = '' +
+ '' +
+ '' +
+ '';
+
+ manifest.rawData.replace(/[\t\r\n]/g, '').indexOf(expectedContentUriRules).should.be.above(-1);
+
+ done();
+ });
+ });
+
+ it('Should add different ACURs from mjs_api_access and mjs_access_whitelist if match setting is different', function (done) {
+ var siteUrl = 'http://url.com/something?query';
+ var shortName = 'shortName';
+
+ var originalManifestInfo = {
+ content: {
+ 'start_url': siteUrl,
+ 'short_name': shortName,
+ 'mjs_access_whitelist': [
+ { 'url': 'http://url.com/otherpath/' }
+ ],
+ 'mjs_api_access': [
+ { 'match': 'http://url.com/somepath/', 'access': 'all' }
+ ]
+ }
+ };
+
+ transformation.convertFromBase(originalManifestInfo, function (err, result) {
+ should.not.exist(err);
+ should.exist(result);
+ /*jshint -W030 */
+ result.should.have.property('content').which.is.an.Object;
+ result.should.have.property('format', 'windows10');
+
+ var manifest = result.content;
+
+ manifest.should.have.property('rawData');
+
+ var expectedContentUriRules = '' +
+ '' +
+ '' +
+ '' +
+ '';
+
+ manifest.rawData.replace(/[\t\r\n]/g, '').indexOf(expectedContentUriRules).should.be.above(-1);
+
+ done();
+ });
+ });
+
+ it('Should add single ACUR from mjs_api_access and mjs_access_whitelist if both have same match setting', function (done) {
+ var siteUrl = 'http://url.com/something?query';
+ var shortName = 'shortName';
+
+ var originalManifestInfo = {
+ content: {
+ 'start_url': siteUrl,
+ 'short_name': shortName,
+ 'mjs_access_whitelist': [
+ { 'url': 'http://url.com/somepath/' }
+ ],
+ 'mjs_api_access': [
+ { 'match': 'http://url.com/somepath/', 'access': 'all' }
+ ]
+ }
+ };
+
+ transformation.convertFromBase(originalManifestInfo, function (err, result) {
+ should.not.exist(err);
+ should.exist(result);
+ /*jshint -W030 */
+ result.should.have.property('content').which.is.an.Object;
+ result.should.have.property('format', 'windows10');
+
+ var manifest = result.content;
+
+ manifest.should.have.property('rawData');
+
+ var expectedContentUriRules = '' +
+ '' +
+ '' +
+ '';
+
+ manifest.rawData.replace(/[\t\r\n]/g, '').indexOf(expectedContentUriRules).should.be.above(-1);
+
+ done();
+ });
+ });
+
+ it('Should add ACUR from mjs_api_access if windows10 is in platform', function (done) {
+ var siteUrl = 'http://url.com/something?query';
+ var shortName = 'shortName';
+
+ var originalManifestInfo = {
+ content: {
+ 'start_url': siteUrl,
+ 'short_name': shortName,
+ 'mjs_api_access': [
+ { 'match': 'http://url.com/somepath/', 'platform': 'windows10', 'access': 'all' }
+ ]
+ }
+ };
+
+ transformation.convertFromBase(originalManifestInfo, function (err, result) {
+ should.not.exist(err);
+ should.exist(result);
+ /*jshint -W030 */
+ result.should.have.property('content').which.is.an.Object;
+ result.should.have.property('format', 'windows10');
+
+ var manifest = result.content;
+
+ manifest.should.have.property('rawData');
+
+ var expectedContentUriRules = '' +
+ '' +
+ '' +
+ '';
+
+ manifest.rawData.replace(/[\t\r\n]/g, '').indexOf(expectedContentUriRules).should.be.above(-1);
+
+ done();
+ });
+ });
+
+ it('Should not add ACUR from mjs_api_access if windows10 is not in platform', function (done) {
+ var siteUrl = 'http://url.com/something?query';
+ var shortName = 'shortName';
+
+ var originalManifestInfo = {
+ content: {
+ 'start_url': siteUrl,
+ 'short_name': shortName,
+ 'mjs_api_access': [
+ { 'match': 'http://url.com/somepath/', 'platform': 'other', 'access': 'all' }
+ ]
+ }
+ };
+
+ transformation.convertFromBase(originalManifestInfo, function (err, result) {
+ should.not.exist(err);
+ should.exist(result);
+ /*jshint -W030 */
+ result.should.have.property('content').which.is.an.Object;
+ result.should.have.property('format', 'windows10');
+
+ var manifest = result.content;
+
+ manifest.should.have.property('rawData');
+
+ var expectedContentUriRules = '' +
+ '' +
+ '';
+
+ manifest.rawData.replace(/[\t\r\n]/g, '').indexOf(expectedContentUriRules).should.be.above(-1);
+
+ done();
+ });
+ });
+
+ it('Should not add ACUR from mjs_api_access if access type is \'none\' and match setting is not whitelisted', function (done) {
+ var siteUrl = 'http://url.com/something?query';
+ var shortName = 'shortName';
+
+ var originalManifestInfo = {
+ content: {
+ 'start_url': siteUrl,
+ 'short_name': shortName,
+ 'mjs_api_access': [
+ { 'match': 'http://url.com/somepath/', 'platform': 'windows10', 'access': 'none' }
+ ]
+ }
+ };
+
+ transformation.convertFromBase(originalManifestInfo, function (err, result) {
+ should.not.exist(err);
+ should.exist(result);
+ /*jshint -W030 */
+ result.should.have.property('content').which.is.an.Object;
+ result.should.have.property('format', 'windows10');
+
+ var manifest = result.content;
+
+ manifest.should.have.property('rawData');
+
+ var expectedContentUriRules = '' +
+ '' +
+ '';
+
+ manifest.rawData.replace(/[\t\r\n]/g, '').indexOf(expectedContentUriRules).should.be.above(-1);
+
+ done();
+ });
+ });
});
});