From 76d873c2b2e6e1df7040a5d493e9732b96112c2a Mon Sep 17 00:00:00 2001 From: Ben Gotow Date: Mon, 27 Jun 2016 10:28:43 -0700 Subject: [PATCH] Reintroduce concept of `provider`, start work on Gmail --- packages/nylas-api/app.js | 2 +- packages/nylas-api/routes/auth.js | 37 +++++++++++--------- packages/nylas-core/config/development.json | 11 ------ packages/nylas-core/index.js | 5 ++- packages/nylas-core/models/shared/account.js | 8 ++--- packages/nylas-sync/sync-worker.js | 15 +++++--- 6 files changed, 40 insertions(+), 38 deletions(-) delete mode 100644 packages/nylas-core/config/development.json diff --git a/packages/nylas-api/app.js b/packages/nylas-api/app.js index 3287e7702..bdc6bd457 100644 --- a/packages/nylas-api/app.js +++ b/packages/nylas-api/app.js @@ -69,6 +69,6 @@ server.register(plugins, (err) => { server.start((startErr) => { if (startErr) { throw startErr; } - console.log('Server running at:', server.info.uri); + console.log('API running at:', server.info.uri); }); }); diff --git a/packages/nylas-api/routes/auth.js b/packages/nylas-api/routes/auth.js index 74e3aa250..4f18c2a87 100644 --- a/packages/nylas-api/routes/auth.js +++ b/packages/nylas-api/routes/auth.js @@ -8,12 +8,10 @@ const { IMAPConnection, DatabaseConnector, SyncPolicy, + Provider, } = require('nylas-core'); -// TODO: Move these to config somehow / somewhere -const CLIENT_ID = '271342407743-nibas08fua1itr1utq9qjladbkv3esdm.apps.googleusercontent.com'; -const CLIENT_SECRET = 'WhmxErj-ei6vJXLocNhBbfBF'; -const REDIRECT_URL = 'http://localhost:5100/auth/gmail/oauthcallback'; +const {GMAIL_CLIENT_ID, GMAIL_CLIENT_SECRET, GMAIL_REDIRECT_URL} = process.env; const SCOPES = [ 'https://www.googleapis.com/auth/userinfo.email', // email address @@ -41,12 +39,13 @@ const exchangeSettings = Joi.object().keys({ eas_server_host: [Joi.string().ip().required(), Joi.string().hostname().required()], }).required(); -const buildAccountWith = ({name, email, settings, credentials}) => { +const buildAccountWith = ({name, email, provider, settings, credentials}) => { return DatabaseConnector.forShared().then((db) => { const {AccountToken, Account} = db; const account = Account.build({ name: name, + provider: provider, emailAddress: email, syncPolicy: SyncPolicy.defaultPolicy(), connectionSettings: settings, @@ -103,6 +102,7 @@ module.exports = (server) => { return buildAccountWith({ name, email, + provider: Provider.IMAP, settings: _.pick(settings, [ 'imap_host', 'imap_port', 'smtp_host', 'smtp_port', @@ -120,9 +120,7 @@ module.exports = (server) => { reply(Serialization.jsonStringify(response)); }) .catch((err) => { - // TODO: Lots more of this - console.log(err) - reply({error: err.toString()}); + reply({error: err.message}).code(400); }) }, }); @@ -137,7 +135,7 @@ module.exports = (server) => { auth: false, }, handler: (request, reply) => { - const oauthClient = new OAuth2(CLIENT_ID, CLIENT_SECRET, REDIRECT_URL); + const oauthClient = new OAuth2(GMAIL_CLIENT_ID, GMAIL_CLIENT_SECRET, GMAIL_REDIRECT_URL); reply.redirect(oauthClient.generateAuthUrl({ access_type: 'offline', prompt: 'consent', @@ -161,16 +159,16 @@ module.exports = (server) => { }, }, handler: (request, reply) => { - const oauthClient = new OAuth2(CLIENT_ID, CLIENT_SECRET, REDIRECT_URL); + const oauthClient = new OAuth2(GMAIL_CLIENT_ID, GMAIL_CLIENT_SECRET, GMAIL_REDIRECT_URL); oauthClient.getToken(request.query.code, (err, tokens) => { if (err) { - reply(err.message).code(400); + reply({error: err.message}).code(400); return; } oauthClient.setCredentials(tokens); google.oauth2({version: 'v2', auth: oauthClient}).userinfo.get((error, profile) => { if (error) { - reply(error.message).code(400); + reply({error: error.message}).code(400); return; } @@ -183,15 +181,21 @@ module.exports = (server) => { const credentials = { access_token: tokens.access_token, refresh_token: tokens.refresh_token, - client_id: CLIENT_ID, - client_secret: CLIENT_SECRET, + client_id: GMAIL_CLIENT_ID, + client_secret: GMAIL_CLIENT_SECRET, } Promise.all([ IMAPConnection.connect({}, Object.assign({}, settings, credentials)), ]) .then(() => - buildAccountWith({name: profile.name, email: profile.email, settings, credentials}) + buildAccountWith({ + name: profile.name, + email: profile.email, + provider: Provider.Gmail, + settings, + credentials, + }) ) .then(({account, token}) => { const response = account.toJSON(); @@ -199,8 +203,7 @@ module.exports = (server) => { reply(Serialization.jsonStringify(response)); }) .catch((connectionErr) => { - // TODO: Lots more of this - reply({error: connectionErr.toString()}); + reply({error: connectionErr.message}).code(400); }); }); }); diff --git a/packages/nylas-core/config/development.json b/packages/nylas-core/config/development.json deleted file mode 100644 index aab9d4b95..000000000 --- a/packages/nylas-core/config/development.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "storage": { - "database": "account-$ACCOUNTID", - "username": null, - "password": null, - "options": { - "dialect": "sqlite", - "storage": "./account-$ACCOUNTID.sqlite" - } - } -} diff --git a/packages/nylas-core/index.js b/packages/nylas-core/index.js index f666976a7..17ce11bd4 100644 --- a/packages/nylas-core/index.js +++ b/packages/nylas-core/index.js @@ -1,11 +1,14 @@ global.Promise = require('bluebird'); module.exports = { + Provider: { + Gmail: 'gmail', + IMAP: 'imap', + }, DatabaseConnector: require('./database-connector'), PubsubConnector: require('./pubsub-connector'), IMAPConnection: require('./imap-connection'), SyncPolicy: require('./sync-policy'), SchedulerUtils: require('./scheduler-utils'), - Config: require(`./config/${process.env.ENV || 'development'}`), ExtendableError: require('./extendable-error'), } diff --git a/packages/nylas-core/models/shared/account.js b/packages/nylas-core/models/shared/account.js index 533f46c57..ec233252b 100644 --- a/packages/nylas-core/models/shared/account.js +++ b/packages/nylas-core/models/shared/account.js @@ -1,12 +1,12 @@ const crypto = require('crypto'); const {JSONType, JSONARRAYType} = require('../../database-types'); -const algorithm = 'aes-256-ctr'; -const password = 'd6F3Efeq'; +const {DB_ENCRYPTION_ALGORITHM, DB_ENCRYPTION_PASSWORD} = process.env; module.exports = (sequelize, Sequelize) => { const Account = sequelize.define('Account', { name: Sequelize.STRING, + provider: Sequelize.STRING, emailAddress: Sequelize.STRING, connectionSettings: JSONType('connectionSettings'), connectionCredentials: Sequelize.STRING, @@ -37,7 +37,7 @@ module.exports = (sequelize, Sequelize) => { if (!(json instanceof Object)) { throw new Error("Call setCredentials with JSON!") } - const cipher = crypto.createCipher(algorithm, password) + const cipher = crypto.createCipher(DB_ENCRYPTION_ALGORITHM, DB_ENCRYPTION_PASSWORD) let crypted = cipher.update(JSON.stringify(json), 'utf8', 'hex') crypted += cipher.final('hex'); @@ -45,7 +45,7 @@ module.exports = (sequelize, Sequelize) => { }, decryptedCredentials: function decryptedCredentials() { - const decipher = crypto.createDecipher(algorithm, password) + const decipher = crypto.createDecipher(DB_ENCRYPTION_ALGORITHM, DB_ENCRYPTION_PASSWORD) let dec = decipher.update(this.connectionCredentials, 'hex', 'utf8') dec += decipher.final('utf8'); diff --git a/packages/nylas-sync/sync-worker.js b/packages/nylas-sync/sync-worker.js index 1d2b8137e..327446fed 100644 --- a/packages/nylas-sync/sync-worker.js +++ b/packages/nylas-sync/sync-worker.js @@ -1,4 +1,5 @@ const { + Provider, SchedulerUtils, IMAPConnection, PubsubConnector, @@ -129,13 +130,19 @@ class SyncWorker { return Category.findAll().then((categories) => { const priority = ['inbox', 'drafts', 'sent'].reverse(); - const categoriesToSync = categories.sort((a, b) => + let categoriesToSync = categories.sort((a, b) => (priority.indexOf(a.role) - priority.indexOf(b.role)) * -1 ) - // const filtered = sorted.filter(cat => - // ['[Gmail]/All Mail', '[Gmail]/Trash', '[Gmail]/Spam'].includes(cat.name) - // ) + if (this._account.provider === Provider.Gmail) { + categoriesToSync = categoriesToSync.filter(cat => + ['[Gmail]/All Mail', '[Gmail]/Trash', '[Gmail]/Spam'].includes(cat.name) + ) + + if (categoriesToSync.length !== 3) { + throw new Error(`Account is missing a core Gmail folder: ${categoriesToSync.join(',')}`) + } + } // TODO Don't accumulate errors, just bail on the first error and clear // the queue and the connection