diff --git a/History.md b/History.md index 24a1e1b252..96a50d4444 100644 --- a/History.md +++ b/History.md @@ -1,4 +1,4 @@ -## vNEXT +## v.NEXT * Subscription handles returned from `Meteor.subscribe` and `TemplateInstance#subscribe` now have a `subscriptionId` property to identify @@ -105,6 +105,33 @@ - MongoDB driver: 1.4.30 (from 1.4.1) - bson: 0.2.18 (from 0.2.7) +### Meteor Mobile updates + +* Upgrade the Cordova CLI dependency from 3.5.1 to 4.2.0. See the release notes + for the 4.x series of the Cordova CLI [on Apache + Cordova](http://cordova.apache.org/announcements/2014/10/16/cordova-4.html). + +* Related to the recently discovered [attack + vectors](http://cordova.apache.org/announcements/2014/08/04/android-351.html) + in Android Cordova apps, Meteor Cordova apps no longer allow access to all + domains by default. If your app access external resources over XHR, you need + to add them to the whitelist of allowed domains with the newly added + [`App.accessRule` + method](https://docs.meteor.com/#/full/App-accessRule) in your + `mobile-config.js` file. + +* Upgrade Cordova Plugins dependencies in Meteor Core packages: + - `org.apache.cordova.file`: from 1.3.0 to 1.3.3 + - `org.apache.cordova.file-transfer`: from 0.4.4 to 0.5.0 + - `org.apache.cordova.splashscreen`: from 0.3.3 to 1.0.0 + - `org.apache.cordova.console`: from 0.2.10 to 0.2.13 + - `org.apache.cordova.device`: from 0.2.11 to 0.3.0 + - `org.apache.cordova.statusbar`: from 0.1.7 to 0.1.10 + - `org.apache.cordova.inappbrowser`: from 0.5.1 to 0.6.0 + - `org.apache.cordova.inappbrowser`: from 0.5.1 to 0.6.0 + +* Use the newer `ios-sim` binary, compiled with Xcode 6 on OS X Mavericks. + ## v.1.0.3.1, 2015-Jan-20 diff --git a/docs/client/data.js b/docs/client/data.js index 291f80bb16..36cb850b66 100644 --- a/docs/client/data.js +++ b/docs/client/data.js @@ -663,6 +663,45 @@ DocsData = { "scope": "global", "summary": "The App configuration object in mobile-config.js" }, + "App.accessRule": { + "kind": "function", + "longname": "App.accessRule", + "memberof": "App", + "name": "accessRule", + "options": [ + { + "description": "

Set to true if the matching URL\nshould be handled externally (e.g. phone app or email client on Android).

", + "name": "launchExternal", + "type": { + "names": [ + "Boolean" + ] + } + } + ], + "params": [ + { + "description": "

The pattern defining affected domains or URLs.

", + "name": "domainRule", + "type": { + "names": [ + "String" + ] + } + }, + { + "name": "options", + "optional": true, + "type": { + "names": [ + "Object" + ] + } + } + ], + "scope": "static", + "summary": "Set a new access rule based on origin domain for your app.\nBy default your application has a limited list of servers it can contact.\nUse this method to extend this list.\n\nDefault access rules:\n\n- `tel:*`, `geo:*`, `mailto:*`, `sms:*`, `market:*` are allowed and\n launch externally (phone app, or an email client on Android)\n- `gap:*`, `cdv:*`, `file:` are allowed (protocols required to access\n local file-system)\n- `http://meteor.local/*` is allowed (a domain Meteor uses to access\n app's assets)\n- The domain of the server passed to the build process (or local ip\n address in the development mode) is used to be able to contact the\n Meteor app server.\n\nRead more about domain patterns in [Cordova\ndocs](http://cordova.apache.org/docs/en/4.0.0/guide_appdev_whitelist_index.md.html).\n\nStarting with Meteor 1.0.4 access rule for all domains and protocols\n(``) is no longer set by default due to\n[certain kind of possible\nattacks](http://cordova.apache.org/announcements/2014/08/04/android-351.html)." + }, "App.configurePlugin": { "kind": "function", "longname": "App.configurePlugin", diff --git a/docs/client/full-api/api/mobile-config.md b/docs/client/full-api/api/mobile-config.md index 98c60c7d6d..3c711dd4c3 100644 --- a/docs/client/full-api/api/mobile-config.md +++ b/docs/client/full-api/api/mobile-config.md @@ -51,7 +51,8 @@ App.configurePlugin('com.phonegap.plugins.facebookconnect', { {{> autoApiBox "App.info"}} {{> autoApiBox "App.setPreference"}} +{{> autoApiBox "App.accessRule"}} {{> autoApiBox "App.configurePlugin"}} {{> autoApiBox "App.icons"}} {{> autoApiBox "App.launchScreens"}} -{{/template}} \ No newline at end of file +{{/template}} diff --git a/docs/client/full-api/tableOfContents.js b/docs/client/full-api/tableOfContents.js index 435b695a65..a992e8003e 100644 --- a/docs/client/full-api/tableOfContents.js +++ b/docs/client/full-api/tableOfContents.js @@ -300,6 +300,7 @@ var toc = [ {name: "mobile-config.js", id: "mobileconfigjs"}, [ {name: "App.info", id: "App-info"}, {name: "App.setPreference", id: "App-setPreference"}, + {name: "App.accessRule", id: "App-accessRule"}, {name: "App.configurePlugin", id: "App-configurePlugin"}, {name: "App.icons", id: "App-icons"}, {name: "App.launchScreens", id: "App-launchScreens"} diff --git a/docs/client/names.json b/docs/client/names.json index f96bb4a456..6357e91a2d 100644 --- a/docs/client/names.json +++ b/docs/client/names.json @@ -22,6 +22,7 @@ "Accounts.validateNewUser", "Accounts.verifyEmail", "App", + "App.accessRule", "App.configurePlugin", "App.icons", "App.info", diff --git a/packages/autoupdate/package.js b/packages/autoupdate/package.js index 49c6164c31..68becb7be2 100644 --- a/packages/autoupdate/package.js +++ b/packages/autoupdate/package.js @@ -4,8 +4,8 @@ Package.describe({ }); Cordova.depends({ - 'org.apache.cordova.file': '1.3.0', - 'org.apache.cordova.file-transfer': '0.4.4' + 'org.apache.cordova.file': '1.3.3', + 'org.apache.cordova.file-transfer': '0.5.0' }); Package.onUse(function (api) { diff --git a/packages/launch-screen/package.js b/packages/launch-screen/package.js index 7bae8683bf..cd6b9e2ebd 100644 --- a/packages/launch-screen/package.js +++ b/packages/launch-screen/package.js @@ -10,7 +10,7 @@ Package.describe({ }); Cordova.depends({ - 'org.apache.cordova.splashscreen': '0.3.3' + 'org.apache.cordova.splashscreen': '1.0.0' }); Package.onUse(function(api) { diff --git a/packages/logging/package.js b/packages/logging/package.js index c7a099fbe9..d1796318e2 100644 --- a/packages/logging/package.js +++ b/packages/logging/package.js @@ -12,7 +12,7 @@ Npm.strip({ }); Cordova.depends({ - 'org.apache.cordova.console': '0.2.10' + 'org.apache.cordova.console': '0.2.13' }); Package.onUse(function (api) { diff --git a/packages/meteor-platform/package.js b/packages/meteor-platform/package.js index 73d54a2dc7..abd4c31546 100644 --- a/packages/meteor-platform/package.js +++ b/packages/meteor-platform/package.js @@ -73,7 +73,3 @@ Package.onUse(function(api) { ], 'web'); }); -Cordova.depends({ - 'org.apache.cordova.device': '0.2.11', - 'com.meteor.cordova-update': 'https://github.com/meteor/com.meteor.cordova-update/tarball/92fe99b7248075318f6446b288995d4381d24cd2' -}); diff --git a/packages/meteor/client_environment.js b/packages/meteor/client_environment.js index 646bf231ef..4e894e0e0f 100644 --- a/packages/meteor/client_environment.js +++ b/packages/meteor/client_environment.js @@ -18,7 +18,8 @@ Meteor = { * @static * @type {Boolean} */ - isServer: false + isServer: false, + isCordova: false }; if (typeof __meteor_runtime_config__ === 'object' && diff --git a/packages/meteor/server_environment.js b/packages/meteor/server_environment.js index 8c950318f7..a4981103cc 100644 --- a/packages/meteor/server_environment.js +++ b/packages/meteor/server_environment.js @@ -1,6 +1,7 @@ Meteor = { isClient: false, - isServer: true + isServer: true, + isCordova: false }; Meteor.settings = {}; diff --git a/packages/mobile-status-bar/package.js b/packages/mobile-status-bar/package.js index d7f1457cfc..a9024eb15d 100644 --- a/packages/mobile-status-bar/package.js +++ b/packages/mobile-status-bar/package.js @@ -8,5 +8,5 @@ Package.onUse(function(api) { }); Cordova.depends({ - 'org.apache.cordova.statusbar': '0.1.7' + 'org.apache.cordova.statusbar': '0.1.10' }); diff --git a/packages/oauth/package.js b/packages/oauth/package.js index a14ff8a77d..ed943d2c92 100644 --- a/packages/oauth/package.js +++ b/packages/oauth/package.js @@ -46,5 +46,6 @@ Package.onTest(function (api) { }); Cordova.depends({ - 'org.apache.cordova.inappbrowser': '0.5.1' + 'org.apache.cordova.inappbrowser': '0.6.0' }); + diff --git a/scripts/dev-bundle-tool-package.js b/scripts/dev-bundle-tool-package.js index 72aa3499f4..0a72ec3d22 100644 --- a/scripts/dev-bundle-tool-package.js +++ b/scripts/dev-bundle-tool-package.js @@ -52,13 +52,7 @@ var packageJson = { // 2.4.0 (more or less, the package.json change isn't committed) plus our PR // https://github.com/williamwicks/node-eachline/pull/4 eachline: "https://github.com/meteor/node-eachline/tarball/ff89722ff94e6b6a08652bf5f44c8fffea8a21da", - - // XXX We install our own fork of cordova because we need a particular patch that - // didn't land to cordova-android yet. As soon as it lands, we can switch back to - // upstream. - // https://github.com/apache/cordova-android/commit/445ddd89fb3269a772978a9860247065e5886249 - // npm install cordova@3.5.0-0.2.6 - "cordova": "https://github.com/meteor/cordova-cli/tarball/0c9b3362c33502ef8f6dba514b87279b9e440543" + cordova: "4.2.0" } }; diff --git a/scripts/generate-dev-bundle.sh b/scripts/generate-dev-bundle.sh index 19061beeff..8b0f380b4a 100755 --- a/scripts/generate-dev-bundle.sh +++ b/scripts/generate-dev-bundle.sh @@ -30,7 +30,8 @@ if [ "$OS" == "osx" ]; then # cp -r build/Release/* "$DIR/lib/ios-sim/" # Download the precompiled tarball - IOS_SIM_URL="https://android-bundle.s3.amazonaws.com/ios-sim.tgz" + # See docs on building the new ios_sim: https://mdg.hackpad.com/Building-ios-sim-tarball-9aHVf0rGcwE + IOS_SIM_URL="http://android-bundle.s3.amazonaws.com/ios-sim.mavericks.xcode6.tgz" curl "$IOS_SIM_URL" | tar xfz - mkdir -p "$DIR/lib/ios-sim" cp -r ios-sim/ios-sim "$DIR/lib/ios-sim" diff --git a/tools/commands-cordova.js b/tools/commands-cordova.js index 57b9b65eed..01407ff194 100644 --- a/tools/commands-cordova.js +++ b/tools/commands-cordova.js @@ -777,7 +777,11 @@ var buildCordova = function (projectContext, platforms, options) { var controlFilePath = files.pathJoin(projectContext.projectDir, 'mobile-config.js'); consumeControlFile( - projectContext, controlFilePath, cordovaPath, options.appName); + projectContext, + controlFilePath, + cordovaPath, + options.appName, + options.host); ensureCordovaPlatforms(projectContext); ensureCordovaPlugins(projectContext, _.extend({}, options, { @@ -1402,8 +1406,9 @@ var launchAndroidSizes = { // Given the mobile control file converts it to the Phongep/Cordova project's // config.xml file and copies the necessary files (icons and launch screens) to // the correct build location. Replaces all the old resources. -var consumeControlFile = function (projectContext, controlFilePath, - cordovaPath, appName) { +var consumeControlFile = function ( + projectContext, controlFilePath, cordovaPath, appName, serverDomain) { + verboseLog('Reading the mobile control file'); // clean up the previous settings and resources files.rm_recursive(files.pathJoin(cordovaPath, 'resources')); @@ -1446,6 +1451,36 @@ var consumeControlFile = function (projectContext, controlFilePath, splash: {} }; + // Default access rules for plain Meteor-Cordova apps. + // Rules can be extended with mobile-config API described below. + // The value is `true` if the protocol or domain should be allowed, + // 'external' if should handled externally. + var accessRules = { + // Allow external calls to things like email client or maps app or a + // phonebook app. + 'tel:*': 'external', + 'geo:*': 'external', + 'mailto:*': 'external', + 'sms:*': 'external', + 'market:*': 'external', + + // phonegap/cordova related protocols + // "file:" protocol is used to access first files from disk + 'file:*': true, + 'cdv:*': true, + 'gap:*': true, + + // allow Meteor's local emulated server url - this is the url from which the + // application loads its assets + 'http://meteor.local/*': true + }; + + // If the remote server domain is known, allow access to it for xhr and DDP + // connections. + if (serverDomain) { + accessRules['*://' + serverDomain + '/*'] = false; + } + var setIcon = function (size, name) { imagePaths.icon[name] = files.pathJoin(iconsPath, size + '.png'); }; @@ -1574,6 +1609,47 @@ var consumeControlFile = function (projectContext, controlFilePath, throw new Error(key + ": unknown key in App.launchScreens configuration."); }); _.extend(imagePaths.splash, launchScreens); + }, + + /** + * @summary Set a new access rule based on origin domain for your app. + * By default your application has a limited list of servers it can contact. + * Use this method to extend this list. + * + * Default access rules: + * + * - `tel:*`, `geo:*`, `mailto:*`, `sms:*`, `market:*` are allowed and + * launch externally (phone app, or an email client on Android) + * - `gap:*`, `cdv:*`, `file:` are allowed (protocols required to access + * local file-system) + * - `http://meteor.local/*` is allowed (a domain Meteor uses to access + * app's assets) + * - The domain of the server passed to the build process (or local ip + * address in the development mode) is used to be able to contact the + * Meteor app server. + * + * Read more about domain patterns in [Cordova + * docs](http://cordova.apache.org/docs/en/4.0.0/guide_appdev_whitelist_index.md.html). + * + * Starting with Meteor 1.0.4 access rule for all domains and protocols + * (``) is no longer set by default due to + * [certain kind of possible + * attacks](http://cordova.apache.org/announcements/2014/08/04/android-351.html). + * + * @param {String} domainRule The pattern defining affected domains or URLs. + * @param {Object} [options] + * @param {Boolean} options.launchExternal Set to true if the matching URL + * should be handled externally (e.g. phone app or email client on Android). + * @memberOf App + */ + accessRule: function (domainRule, options) { + options = options || {}; + options.launchExternal = !! options.launchExternal; + if (options.launchExternal) { + accessRules[domainRule] = 'external'; + } else { + accessRules[domainRule] = true; + } } }; @@ -1617,8 +1693,15 @@ var consumeControlFile = function (projectContext, controlFilePath, // load from index.html by default config.ele('content', { src: 'index.html' }); - // allow cors for the initial file - config.ele('access', { origin: '*' }); + + // Copy all the access rules + _.each(accessRules, function (rule, pattern) { + var opts = { origin: pattern }; + if (rule === 'external') + opts['launch-external'] = true; + + config.ele('access', opts); + }); var iosPlatform = config.ele('platform', { name: 'ios' }); var androidPlatform = config.ele('platform', { name: 'android' });