diff --git a/res/build_cca.sh b/res/build_cca.sh
new file mode 100755
index 0000000..77ef8a7
--- /dev/null
+++ b/res/build_cca.sh
@@ -0,0 +1,11 @@
+#!/bin/sh
+
+# go to root
+cd `dirname $0`
+cd ..
+
+DIR=release/cca
+
+rm -rf $DIR
+mkdir -p $DIR
+cca create $DIR/Whiteout --link-to=dist/manifest.json
\ No newline at end of file
diff --git a/res/run_cca.sh b/res/run_cca.sh
new file mode 100755
index 0000000..1469131
--- /dev/null
+++ b/res/run_cca.sh
@@ -0,0 +1,9 @@
+#!/bin/sh
+
+# go to root
+cd `dirname $0`
+cd ..
+
+cd release/cca/Whiteout
+#cca run ios
+cca run android
\ No newline at end of file
diff --git a/src/js/bo/auth.js b/src/js/bo/auth.js
index 5fe7f79..d1ea01d 100644
--- a/src/js/bo/auth.js
+++ b/src/js/bo/auth.js
@@ -19,24 +19,32 @@ define(function() {
return;
}
- // get a fresh oauth token
- self._oauth.getOAuthToken(function(err, token) {
+ // try reading email address from local storage
+ self.getEmailAddressFromConfig(function(err, emailAddress) {
if (err) {
callback(err);
return;
}
- // get email address for the token
- self.queryEmailAddress(token, function(err, emailAddress) {
+ // get a fresh oauth token
+ self._oauth.getOAuthToken(emailAddress, function(err, token) {
if (err) {
callback(err);
return;
}
- callback(null, {
- emailAddress: emailAddress,
- oauthToken: token,
- sslCert: certificate
+ // get email address for the token
+ self.queryEmailAddress(token, function(err, emailAddress) {
+ if (err) {
+ callback(err);
+ return;
+ }
+
+ callback(null, {
+ emailAddress: emailAddress,
+ oauthToken: token,
+ sslCert: certificate
+ });
});
});
});
diff --git a/src/js/controller/mail-list.js b/src/js/controller/mail-list.js
index 02aa61b..8afdb87 100644
--- a/src/js/controller/mail-list.js
+++ b/src/js/controller/mail-list.js
@@ -53,10 +53,7 @@ define(function(require) {
}
$scope.state.mailList.selected = email;
- $timeout(function() {
- // toogle read ste in next digest step to speed up css transition to read mode
- $scope.state.read.toggle(true);
- });
+ $scope.state.read.toggle(true);
keychainDao.refreshKeyForUserId(email.from[0].address, onKeyRefreshed);
@@ -465,7 +462,7 @@ define(function(require) {
'>> from 0.7.0.1\n' +
'>>\n' +
'>> God speed!'; // plaintext body
- this.html = '
---------- Forwarded message ----------
From:
MunichJS User Group <info@meetup.com>Date: Thu, May 8, 2014 at 11:10 PM
Subject: Stay in touch!
To:
mail@john.com | Axel Rauschmayer Organizer |
';
+ this.html = 'Hello there
';
this.encrypted = true;
this.decrypted = true;
};
diff --git a/src/js/util/oauth.js b/src/js/util/oauth.js
index f37af8c..6ccda2e 100644
--- a/src/js/util/oauth.js
+++ b/src/js/util/oauth.js
@@ -12,19 +12,34 @@ define(function() {
/**
* Request an OAuth token from chrome for gmail users
*/
- OAuth.prototype.getOAuthToken = function(callback) {
- // get OAuth Token from chrome
- chrome.identity.getAuthToken({
- 'interactive': true
- }, function(token) {
- if ((chrome && chrome.runtime && chrome.runtime.lastError) || !token) {
- callback({
- errMsg: 'Error fetching an OAuth token for the user!'
- });
+ OAuth.prototype.getOAuthToken = function(emailAddress, callback) {
+ var idOptions = {
+ interactive: true
+ };
+
+ // check which runtime the app is running under
+ chrome.runtime.getPlatformInfo(function(platformInfo) {
+ if ((chrome && chrome.runtime && chrome.runtime.lastError) || !platformInfo) {
+ callback(new Error('Error getting chrome platform info!'));
return;
}
- callback(null, token);
+ if (emailAddress && platformInfo.os.indexOf('android') !== -1) {
+ // set accountHint so that native Android account picker does not show up each time
+ idOptions.accountHint = emailAddress;
+ }
+
+ // get OAuth Token from chrome
+ chrome.identity.getAuthToken(idOptions, function(token) {
+ if ((chrome && chrome.runtime && chrome.runtime.lastError) || !token) {
+ callback({
+ errMsg: 'Error fetching an OAuth token for the user!'
+ });
+ return;
+ }
+
+ callback(null, token);
+ });
});
};
@@ -38,7 +53,7 @@ define(function() {
// fetch gmail user's email address from the Google Authorization Server
this._googleApi.get({
- uri: '/oauth2/v1/tokeninfo?access_token=' + token
+ uri: '/oauth2/v3/userinfo?access_token=' + token
}, function(err, info) {
if (err || !info || !info.email) {
callback({
diff --git a/src/manifest.json b/src/manifest.json
index dd23507..bd841e9 100644
--- a/src/manifest.json
+++ b/src/manifest.json
@@ -13,6 +13,7 @@
},
"notifications",
"https://keys-test.whiteout.io/",
+ "https://www.googleapis.com/",
"identity", {
"socket": [
"tcp-connect:imap.gmail.com:993",
@@ -24,7 +25,7 @@
"oauth2": {
"client_id": "440907777130.apps.googleusercontent.com",
"scopes": [
- "https://www.googleapis.com/auth/userinfo.email",
+ "email",
"https://mail.google.com/"
]
},
diff --git a/src/manifest.mobile.json b/src/manifest.mobile.json
new file mode 100644
index 0000000..d081891
--- /dev/null
+++ b/src/manifest.mobile.json
@@ -0,0 +1,12 @@
+{
+ "packageId": "io.whiteout.WhiteoutMail",
+ "versionCode": 1,
+ "CFBundleVersion": "1.1.1",
+
+ // platform overrides
+ "ios": {
+ "oauth2": {
+ "client_id": "440907777130-m0cn01eot554ik1h70hfcmvidnq61oer.apps.googleusercontent.com"
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/sass/components/_layout.scss b/src/sass/components/_layout.scss
index 9ed7d85..d4a2e33 100755
--- a/src/sass/components/_layout.scss
+++ b/src/sass/components/_layout.scss
@@ -1,29 +1,25 @@
.main-content {
@include clearfix();
height: 100%;
- overflow: hidden;
- backface-visibility: hidden;
-
- // double in modile to allow slide transition
- @include respond-to(mobile) {
- width: 200%; // this currently causes a smear effect bug on mail-list header in safari
- transition: transform $time-nav-animation ease-in-out;
- }
}
.column {
height: 100%;
overflow: hidden;
- // half of main-content in mobile mode to allow slide transition
@include respond-to(mobile) {
- width: 50%;
+ display: none;
+ width: 100%;
}
}
.column-left {
float: left;
+ @include respond-to(mobile) {
+ display: block;
+ }
+
@include respond-to(desktop) {
width: $content-nav-width;
border-right: 1px solid $color-grey-light;
@@ -32,6 +28,11 @@
.shift-right {
@include respond-to(mobile) {
- transform: translateX(-50%);
+ .column {
+ display: block;
+ }
+ .column-left {
+ display: none;
+ }
}
}
\ No newline at end of file
diff --git a/test/unit/auth-test.js b/test/unit/auth-test.js
index 9d39b51..bfd85e3 100644
--- a/test/unit/auth-test.js
+++ b/test/unit/auth-test.js
@@ -20,17 +20,19 @@ define(function(require) {
afterEach(function() {});
describe('getCredentials', function() {
- var getCertificateStub, queryEmailAddressStub;
+ var getCertificateStub, queryEmailAddressStub, getEmailAddressFromConfigStub;
beforeEach(function() {
getCertificateStub = sinon.stub(auth, 'getCertificate');
queryEmailAddressStub = sinon.stub(auth, 'queryEmailAddress');
+ getEmailAddressFromConfigStub = sinon.stub(auth, 'getEmailAddressFromConfig');
});
it('should work', function(done) {
getCertificateStub.yields(null, 'cert');
+ getEmailAddressFromConfigStub.yields(null, 'asdf@example.com');
queryEmailAddressStub.withArgs('token').yields(null, 'asdf@example.com');
- oauthStub.getOAuthToken.yields(null, 'token');
+ oauthStub.getOAuthToken.withArgs('asdf@example.com').yields(null, 'token');
auth.getCredentials({}, function(err, credentials) {
expect(err).to.not.exist;
@@ -53,6 +55,7 @@ define(function(require) {
it('should fail due to error in getOAuthToken', function(done) {
getCertificateStub.yields(null, 'cert');
+ getEmailAddressFromConfigStub.yields(null, 'asdf@example.com');
oauthStub.getOAuthToken.yields(new Error());
auth.getCredentials({}, function(err, credentials) {
@@ -64,6 +67,7 @@ define(function(require) {
it('should fail due to error in queryEmailAddress', function(done) {
getCertificateStub.yields(null, 'cert');
+ getEmailAddressFromConfigStub.yields(null, 'asdf@example.com');
queryEmailAddressStub.withArgs('token').yields(new Error());
oauthStub.getOAuthToken.yields(null, 'token');
diff --git a/test/unit/oauth-test.js b/test/unit/oauth-test.js
index daea932..84f8cae 100644
--- a/test/unit/oauth-test.js
+++ b/test/unit/oauth-test.js
@@ -6,22 +6,31 @@ define(function(require) {
expect = chai.expect;
describe('OAuth unit tests', function() {
- var oauth, googleApiStub, identityStub;
+ var oauth, googleApiStub, identityStub, getPlatformInfoStub,
+ testEmail = 'test@example.com';
beforeEach(function() {
googleApiStub = sinon.createStubInstance(RestDAO);
oauth = new OAuth(googleApiStub);
window.chrome = window.chrome || {};
+
window.chrome.identity = window.chrome.identity || {};
if (typeof window.chrome.identity.getAuthToken !== 'function') {
window.chrome.identity.getAuthToken = function() {};
}
identityStub = sinon.stub(window.chrome.identity, 'getAuthToken');
+
+ window.chrome.runtime = window.chrome.runtime || {};
+ if (typeof window.chrome.runtime.getPlatformInfo !== 'function') {
+ window.chrome.runtime.getPlatformInfo = function() {};
+ }
+ getPlatformInfoStub = sinon.stub(window.chrome.runtime, 'getPlatformInfo');
});
afterEach(function() {
identityStub.restore();
+ getPlatformInfoStub.restore();
});
describe('isSupported', function() {
@@ -31,10 +40,46 @@ define(function(require) {
});
describe('getOAuthToken', function() {
- it('should work', function(done) {
- identityStub.yields('token');
+ it('should work for empty emailAddress', function(done) {
+ getPlatformInfoStub.yields({
+ os: 'android'
+ });
+ identityStub.withArgs({
+ interactive: true
+ }).yields('token');
- oauth.getOAuthToken(function(err, token) {
+ oauth.getOAuthToken(undefined, function(err, token) {
+ expect(err).to.not.exist;
+ expect(token).to.equal('token');
+ done();
+ });
+ });
+
+ it('should work on android app', function(done) {
+ getPlatformInfoStub.yields({
+ os: 'android'
+ });
+ identityStub.withArgs({
+ interactive: true,
+ accountHint: testEmail
+ }).yields('token');
+
+ oauth.getOAuthToken(testEmail, function(err, token) {
+ expect(err).to.not.exist;
+ expect(token).to.equal('token');
+ done();
+ });
+ });
+
+ it('should work on desktop chrome', function(done) {
+ getPlatformInfoStub.yields({
+ os: 'mac'
+ });
+ identityStub.withArgs({
+ interactive: true
+ }).yields('token');
+
+ oauth.getOAuthToken(testEmail, function(err, token) {
expect(err).to.not.exist;
expect(token).to.equal('token');
done();
@@ -42,9 +87,12 @@ define(function(require) {
});
it('should fail', function(done) {
+ getPlatformInfoStub.yields({
+ os: 'android'
+ });
identityStub.yields();
- oauth.getOAuthToken(function(err, token) {
+ oauth.getOAuthToken(testEmail, function(err, token) {
expect(err).to.exist;
expect(token).to.not.exist;
done();
@@ -55,7 +103,7 @@ define(function(require) {
describe('queryEmailAddress', function() {
it('should work', function(done) {
googleApiStub.get.withArgs({
- uri: '/oauth2/v1/tokeninfo?access_token=token'
+ uri: '/oauth2/v3/userinfo?access_token=token'
}).yields(null, {
email: 'asdf@example.com'
});
@@ -77,7 +125,7 @@ define(function(require) {
it('should fail due to error in rest api', function(done) {
googleApiStub.get.withArgs({
- uri: '/oauth2/v1/tokeninfo?access_token=token'
+ uri: '/oauth2/v3/userinfo?access_token=token'
}).yields(new Error());
oauth.queryEmailAddress('token', function(err, emailAddress) {