diff --git a/.gitignore b/.gitignore index 97c8c33..4935eac 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ /node_modules/ +/scripts/node_modules/ npm-debug.log coverage.html .ntvs_analysis.dat diff --git a/package.json b/package.json index df0e32e..4453c58 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "cordova-plugin-hostedwebapp", - "version": "0.1.1", + "version": "0.1.2", "description": "Hosted Web App Plugin", "cordova": { "id": "cordova-plugin-hostedwebapp", diff --git a/plugin.xml b/plugin.xml index 623f83f..c425570 100644 --- a/plugin.xml +++ b/plugin.xml @@ -1,7 +1,7 @@ + version="0.1.2"> HostedWebApp Hosted Web App Plugin MIT License diff --git a/scripts/test/assets/fullUrlForScope/config.xml b/scripts/test/assets/fullUrlForScope/config.xml new file mode 100644 index 0000000..309a182 --- /dev/null +++ b/scripts/test/assets/fullUrlForScope/config.xml @@ -0,0 +1,3 @@ + + + diff --git a/scripts/test/assets/fullUrlForScope/manifest.json b/scripts/test/assets/fullUrlForScope/manifest.json new file mode 100644 index 0000000..c53769a --- /dev/null +++ b/scripts/test/assets/fullUrlForScope/manifest.json @@ -0,0 +1,7 @@ +{ + "start_url": "http://wat-docs.azurewebsites.net/", + "name": "WAT Documentation", + "orientation": "landscape", + "display": "fullscreen", + "scope": "http://www.domain.com" +} diff --git a/scripts/test/assets/jsonEmpty/www/empty.txt b/scripts/test/assets/fullUrlForScope/www/empty.txt similarity index 100% rename from scripts/test/assets/jsonEmpty/www/empty.txt rename to scripts/test/assets/fullUrlForScope/www/empty.txt diff --git a/scripts/test/assets/jsonEmpty/manifest.json b/scripts/test/assets/jsonEmpty/manifest.json deleted file mode 100644 index f3ee419..0000000 --- a/scripts/test/assets/jsonEmpty/manifest.json +++ /dev/null @@ -1,2 +0,0 @@ -{ -} diff --git a/scripts/test/assets/jsonEmpty/config.xml b/scripts/test/assets/jsonPropertiesMissing/config.xml similarity index 100% rename from scripts/test/assets/jsonEmpty/config.xml rename to scripts/test/assets/jsonPropertiesMissing/config.xml diff --git a/scripts/test/assets/jsonPropertiesMissing/manifest.json b/scripts/test/assets/jsonPropertiesMissing/manifest.json new file mode 100644 index 0000000..7247868 --- /dev/null +++ b/scripts/test/assets/jsonPropertiesMissing/manifest.json @@ -0,0 +1,3 @@ +{ + "start_url": "http://wat-docs.azurewebsites.net/" +} diff --git a/scripts/test/assets/jsonPropertiesMissing/www/empty.txt b/scripts/test/assets/jsonPropertiesMissing/www/empty.txt new file mode 100644 index 0000000..50c5405 --- /dev/null +++ b/scripts/test/assets/jsonPropertiesMissing/www/empty.txt @@ -0,0 +1 @@ +empty folder \ No newline at end of file diff --git a/scripts/test/assets/wildcardSubdomainForScope/config.xml b/scripts/test/assets/wildcardSubdomainForScope/config.xml new file mode 100644 index 0000000..309a182 --- /dev/null +++ b/scripts/test/assets/wildcardSubdomainForScope/config.xml @@ -0,0 +1,3 @@ + + + diff --git a/scripts/test/assets/wildcardSubdomainForScope/manifest.json b/scripts/test/assets/wildcardSubdomainForScope/manifest.json new file mode 100644 index 0000000..73a0376 --- /dev/null +++ b/scripts/test/assets/wildcardSubdomainForScope/manifest.json @@ -0,0 +1,7 @@ +{ + "start_url": "http://wat-docs.azurewebsites.net/", + "name": "WAT Documentation", + "orientation": "landscape", + "display": "fullscreen", + "scope": "http://*.domain.com" +} diff --git a/scripts/test/assets/wildcardSubdomainForScope/www/empty.txt b/scripts/test/assets/wildcardSubdomainForScope/www/empty.txt new file mode 100644 index 0000000..50c5405 --- /dev/null +++ b/scripts/test/assets/wildcardSubdomainForScope/www/empty.txt @@ -0,0 +1 @@ +empty folder \ No newline at end of file diff --git a/scripts/test/updateConfigurationBeforePrepare.js b/scripts/test/updateConfigurationBeforePrepare.js index db6ff93..12566e3 100644 --- a/scripts/test/updateConfigurationBeforePrepare.js +++ b/scripts/test/updateConfigurationBeforePrepare.js @@ -59,7 +59,7 @@ function initializeContext(testDir) { return ctx; } -describe('updateConfiguration.js', function (){ +describe('updateConfigurationBeforePrepare.js', function (){ beforeEach(function () { tu.copyRecursiveSync(assetsDirectory, workingDirectory); }); @@ -104,7 +104,7 @@ describe('updateConfiguration.js', function (){ }); it('Should not update name if it is missing in manifest.json', function (done) { - var testDir = path.join(workingDirectory, 'jsonEmpty'); + var testDir = path.join(workingDirectory, 'jsonPropertiesMissing'); var configXML = path.join(testDir, 'config.xml'); var ctx = initializeContext(testDir); @@ -146,7 +146,7 @@ describe('updateConfiguration.js', function (){ }); it('Should not update orientation if it is missing in manifest.json', function (done){ - var testDir = path.join(workingDirectory, 'jsonEmpty'); + var testDir = path.join(workingDirectory, 'jsonPropertiesMissing'); var configXML = path.join(testDir, 'config.xml'); var ctx = initializeContext(testDir); @@ -187,7 +187,7 @@ describe('updateConfiguration.js', function (){ }); it('Should not update fullscreen if it is missing in manifest.json', function (done){ - var testDir = path.join(workingDirectory, 'jsonEmpty'); + var testDir = path.join(workingDirectory, 'jsonPropertiesMissing'); var configXML = path.join(testDir, 'config.xml'); var ctx = initializeContext(testDir); @@ -214,7 +214,7 @@ describe('updateConfiguration.js', function (){ }); it('Should keep existing access rules unchanged in config.xml', function (done){ - var testDir = path.join(workingDirectory, 'jsonEmpty'); + var testDir = path.join(workingDirectory, 'jsonPropertiesMissing'); var configXML = path.join(testDir, 'config.xml'); var ctx = initializeContext(testDir); @@ -267,7 +267,7 @@ describe('updateConfiguration.js', function (){ }); }); - it('Should add access rules for scope in config.xml', function (done){ + it('Should add access rules for scope in config.xml if scope is a relative URL', function (done){ var testDir = path.join(workingDirectory, 'xmlEmptyWidget'); var configXML = path.join(testDir, 'config.xml'); var ctx = initializeContext(testDir); @@ -286,6 +286,44 @@ describe('updateConfiguration.js', function (){ }); }); + it('Should add access rules for scope in config.xml if scope is a full URL', function (done){ + var testDir = path.join(workingDirectory, 'fullUrlForScope'); + var configXML = path.join(testDir, 'config.xml'); + var ctx = initializeContext(testDir); + + updateConfiguration(ctx).then(function () { + var content = fs.readFileSync(configXML).toString(); + + // rules for android + assert(content.match(/[\s\S]*[\s\S]*<\/platform>/)); + assert(content.match(/[\s\S]*[\s\S]*<\/platform>/)); + + // rules for ios + assert(content.match(/[\s\S]*[\s\S]*<\/platform>/)); + + done(); + }); + }); + + it('Should add access rules for scope in config.xml if scope is a full URL with wildcard as subdomain', function (done){ + var testDir = path.join(workingDirectory, 'wildcardSubdomainForScope'); + var configXML = path.join(testDir, 'config.xml'); + var ctx = initializeContext(testDir); + + updateConfiguration(ctx).then(function () { + var content = fs.readFileSync(configXML).toString(); + + // rules for android + assert(content.match(/[\s\S]*[\s\S]*<\/platform>/)); + assert(content.match(/[\s\S]*[\s\S]*<\/platform>/)); + + // rules for ios + assert(content.match(/[\s\S]*[\s\S]*<\/platform>/)); + + done(); + }); + }); + it('Should add access rules from mjs_access_whitelist list', function (done){ var testDir = path.join(workingDirectory, 'xmlEmptyWidget'); var configXML = path.join(testDir, 'config.xml'); diff --git a/scripts/updateConfigurationBeforePrepare.js b/scripts/updateConfigurationBeforePrepare.js index a19c453..1f59c9b 100644 --- a/scripts/updateConfigurationBeforePrepare.js +++ b/scripts/updateConfigurationBeforePrepare.js @@ -155,10 +155,18 @@ function processAccessRules(manifest) { // determine base rule based on the start_url and the scope var baseUrlPattern = manifest.start_url; if (manifest.scope && manifest.scope.length) { - baseUrlPattern = url.resolve(baseUrlPattern, manifest.scope); + var parsedScopeUrl = url.parse(manifest.scope); + if (parsedScopeUrl.protocol) { + baseUrlPattern = manifest.scope; + } else { + baseUrlPattern = url.resolve(baseUrlPattern, manifest.scope); + } } - baseUrlPattern = url.resolve(baseUrlPattern, '*'); + // If there are no wildcards in the pattern, add '*' at the end + if (baseUrlPattern.indexOf('*') === -1) { + baseUrlPattern = url.resolve(baseUrlPattern, '*'); + } // add base rule as an access rule for Android var androidAccessBaseRule = new etree.SubElement(androidRoot, 'access'); @@ -594,7 +602,7 @@ module.exports = function (context) { var manifestPath = path.join(projectRoot, 'manifest.json'); fs.readFile(manifestPath, function (err, data) { if (err) { - logger.error('ERROR: Failed to read manifest in at \'' + manifestPath + '\'.'); + logger.error('Failed to read manifest at \'' + manifestPath + '\'.'); return task.reject(err); } @@ -602,12 +610,26 @@ module.exports = function (context) { var appManifestPath = path.join(projectRoot, 'www', 'manifest.json'); fs.writeFile(appManifestPath, manifestJson, function (err) { if (err) { - logger.error('ERROR: Failed to copy manifest to \'www\' folder.'); + logger.error('Failed to copy manifest to \'www\' folder.'); return task.reject(err); } var manifest = JSON.parse(manifestJson); + // The start_url member is required and must be a full URL. + // Even though a relative URL is a valid according to the W3C spec, a full URL + // is needed because the plugin cannot determine the manifest's origin. + var start_url; + if (manifest.start_url) { + start_url = url.parse(manifest.start_url); + } + + if (!(start_url && start_url.hostname && start_url.protocol)) { + logger.error('Invalid or incomplete W3C manifest.'); + var err = new Error('The start_url member in the manifest is required and must be a full URL.'); + return task.reject(err); + } + // update name, start_url, orientation, and fullscreen from manifest if (manifest.short_name) { config.setName(manifest.short_name.replace(/\//g,'').replace(/\s/g,''));