Skip to content

Commit

Permalink
feat(gmail-api): Alpha version of Gmail API support
Browse files Browse the repository at this point in the history
  • Loading branch information
andris9 committed May 30, 2024
1 parent f641a6e commit f7fd60a
Show file tree
Hide file tree
Showing 8 changed files with 59 additions and 34 deletions.
19 changes: 17 additions & 2 deletions lib/account.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,9 @@ class Account {
} else {
accountData.type = 'oauth2';
}
if (app.baseScopes === 'api') {
accountData.isApi = true;
}
} else if (accountData.imap && !accountData.imap.disabled) {
accountData.type = 'imap';
} else {
Expand All @@ -96,7 +99,10 @@ class Account {
accountData.oauth2 && accountData.oauth2.provider && accountData.oauth2.provider !== accountData.type
? accountData.oauth2.provider
: undefined,
state: !runIndex || runIndex <= accountData.runIndex || ['init', 'unset'].includes(accountData.state) ? accountData.state : 'init',
state:
!runIndex || runIndex <= accountData.runIndex || ['init', 'unset'].includes(accountData.state) || accountData.isApi
? accountData.state
: 'init',

webhooks: accountData.webhooks || undefined,
proxy: accountData.proxy || undefined,
Expand Down Expand Up @@ -454,7 +460,16 @@ class Account {

let accountData = this.unserializeAccountData(result);

accountData.state = !runIndex || runIndex <= accountData.runIndex || ['init', 'unset'].includes(accountData.state) ? accountData.state : 'init';
if (accountData.oauth2 && accountData.oauth2.provider) {
let app = await oauth2Apps.get(accountData.oauth2.provider);
if (app.baseScopes === 'api') {
accountData.isApi = true;
}
accountData._app = app;
}

accountData.state =
!runIndex || runIndex <= accountData.runIndex || ['init', 'unset'].includes(accountData.state) || accountData.isApi ? accountData.state : 'init';

if (requireValid && !['connected', 'connecting', 'syncing'].includes(accountData.state)) {
let err;
Expand Down
19 changes: 8 additions & 11 deletions lib/imap-connection.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ const socks = require('socks');
const { Gateway } = require('./gateway');

const { oauth2Apps, oauth2ProviderData } = require('./oauth2-apps');
const featureFlags = require('./feature-flags');
const { BaseClient } = require('./api-client/base-client');

const { Subconnection } = require('./subconnection');
Expand Down Expand Up @@ -854,16 +853,14 @@ class IMAPConnection extends BaseClient {

let oauth2User = accountData.oauth2.auth.delegatedUser || accountData.oauth2.auth.user;

if (featureFlags.enabled('gmail api')) {
if (oauth2App.baseScopes === 'api') {
return {
type: 'api',
app: oauth2App.id,
provider: providerData.provider,
user: oauth2User,
accessToken
};
}
if (oauth2App.baseScopes === 'api') {
return {
type: 'api',
app: oauth2App.id,
provider: providerData.provider,
user: oauth2User,
accessToken
};
}

imapConnectionConfig = Object.assign(
Expand Down
9 changes: 7 additions & 2 deletions lib/routes-ui.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,6 @@ const speakeasy = require('speakeasy');
const base32 = require('base32.js');
const { simpleParser } = require('mailparser');
const libmime = require('libmime');
const featureFlags = require('./feature-flags');

let pfStructuredClone = typeof structuredClone === 'function' ? structuredClone : data => JSON.parse(JSON.stringify(data));

Expand Down Expand Up @@ -345,7 +344,7 @@ const oauthUpdateSchema = {
baseScopes: Joi.string()
.empty('')
.trim()
.valid(...['imap'].concat(featureFlags.enabled('gmail api') ? 'api' : []))
.valid(...['imap', 'api'])
.example('imap')
.description('OAuth2 Base Scopes'),

Expand Down Expand Up @@ -7244,6 +7243,8 @@ ${Buffer.from(data.content, 'base64url').toString('base64')}
values,
availablePaths: JSON.stringify(mailboxes.map(entry => entry.path)),

isApi: accountData.isApi,

hasIMAPPass: accountData.imap && accountData.imap.auth && !!accountData.imap.auth.pass,
hasSMTPPass: accountData.smtp && accountData.smtp.auth && !!accountData.smtp.auth.pass,
defaultSmtpEhloName: await getServiceHostname()
Expand Down Expand Up @@ -7375,6 +7376,8 @@ ${Buffer.from(data.content, 'base64url').toString('base64')}
account: request.params.account,
availablePaths: JSON.stringify(mailboxes.map(entry => entry.path)),

isApi: accountData.isApi,

hasIMAPPass: accountData.imap && accountData.imap.auth && !!accountData.imap.auth.pass,
hasSMTPPass: accountData.smtp && accountData.smtp.auth && !!accountData.smtp.auth.pass,
defaultSmtpEhloName: await getServiceHostname()
Expand Down Expand Up @@ -7421,6 +7424,8 @@ ${Buffer.from(data.content, 'base64url').toString('base64')}
errors,
availablePaths: JSON.stringify(mailboxes.map(entry => entry.path)),

isApi: accountData.isApi,

hasIMAPPass: accountData.imap && accountData.imap.auth && !!accountData.imap.auth.pass,
hasSMTPPass: accountData.smtp && accountData.smtp.auth && !!accountData.smtp.auth.pass,
defaultSmtpEhloName: await getServiceHostname()
Expand Down
3 changes: 1 addition & 2 deletions lib/schemas.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ const Joi = require('joi');
const config = require('wild-config');
const { getByteSize } = require('./tools');
const { locales } = require('./translations');
const featureFlags = require('./feature-flags');

const RESYNC_DELAY = 15 * 60;

Expand Down Expand Up @@ -1162,7 +1161,7 @@ const oauthCreateSchema = {
baseScopes: Joi.string()
.empty('')
.trim()
.valid(...['imap'].concat(featureFlags.enabled('gmail api') ? 'api' : []))
.valid(...['imap', 'api'])
.example('imap')
.description('OAuth2 Base Scopes'),

Expand Down
23 changes: 15 additions & 8 deletions views/accounts/account.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -185,13 +185,12 @@
</div>
</div>



{{#if account.oauth2.provider}}

<div class="card mb-4">
<div class="card-header py-3">
<h6 class="m-0 font-weight-bold text-primary">OAuth2</h6>
<h6 class="m-0 font-weight-bold text-primary">OAuth2
</h6>
</div>
<div class="card-body">

Expand All @@ -212,7 +211,7 @@

<dl class="row">

{{#if account.oauth2.provider}}

<dt class="col-sm-3">Provider</dt>

{{#if account.oauth2.app}}
Expand All @@ -227,16 +226,20 @@
data-content="{{account.oauth2.app.meta.authFlag.message}}"><i
class="fas fa-exclamation-triangle text-danger"></i></a>


{{/if}}


</dd>
{{else}}
<dd class="col-sm-9">{{account.type.comment}}</dd>
{{/if}}

{{/if}}
<dt class="col-sm-3">Connection method</dt>
<dd class="col-sm-9">
{{#if account.isApi}}
API
{{else}}
IMAP
{{/if}}
</dd>

{{#if account.oauth2.auth.user}}
<dt class="col-sm-3">Username</dt>
Expand Down Expand Up @@ -277,6 +280,8 @@

{{/if}}

{{#unless account.isApi}}

<div class="card mb-4">
<div class="card-header py-3">
<h6 class="m-0 font-weight-bold text-primary">IMAP</h6>
Expand Down Expand Up @@ -589,6 +594,8 @@

{{/if}}

{{/unless}}

{{#if showAdvanced}}
<div class="card mb-4">
<div class="card-header py-3">
Expand Down
4 changes: 4 additions & 0 deletions views/accounts/edit.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@
</div>
</div>

{{#unless isApi}}

{{#if values.imap}}
<input type="hidden" name="imap" value="on">

Expand Down Expand Up @@ -231,6 +233,8 @@
</div>
{{/if}}

{{/unless}}

<div class="card mb-4">

<div class="card-header py-3">
Expand Down
14 changes: 6 additions & 8 deletions views/partials/oauth_form.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -188,11 +188,7 @@
</div>
</div>

{{#featureFlag "gmail api"}}
{{! show this section only if the Gmail API feature flag is enabled}}

{{#if activeGmail}}

<div class="card mb-4">

<div class="card-header py-3">
Expand All @@ -204,18 +200,21 @@
<input class="form-check-input" type="radio" name="baseScopes" id="baseScopesImap" value="imap" {{#unless
baseScopesApi}}checked{{/unless}}>
<label class="form-check-label" for="baseScopesImap">
IMAP and SMTP
IMAP and SMTP &mdash; <em class="text-muted">https://mail.google.com/</em>
</label>
</div>
<div class="form-check">
<input class="form-check-input" type="radio" name="baseScopes" id="baseScopesAPI" value="api" {{#if
baseScopesApi}}checked{{/if}}>
<label class="form-check-label" for="baseScopesAPI">
Gmail API
Gmail API <span class="badge badge-danger" style="cursor:default;" data-toggle="popover"
data-trigger="hover" data-title="Alpha feature"
data-content="This feature is not stable; it has many bugs, and its behavior will change in the future. Use it for testing purposes only.">
Alpha feature
</span> &mdash; <em class="text-muted">/auth/gmail.modify</em>
</label>
</div>


</div>

<div class="card-footer text-muted">
Expand All @@ -225,7 +224,6 @@
</div>
</div>
{{/if}}
{{/featureFlag}}

<div class="card mb-4">
<a href="#setupScopes" class="d-block card-header py-3 {{#unless values.extraScopes}} collapsed{{/unless}}"
Expand Down
2 changes: 1 addition & 1 deletion workers/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -6493,7 +6493,7 @@ When making API calls remember that requests against the same account are queued
baseScopes: Joi.string()
.empty('')
.trim()
.valid(...['imap'].concat(featureFlags.enabled('gmail api') ? 'api' : []))
.valid(...['imap', 'api'])
.example('imap')
.description('OAuth2 Base Scopes'),

Expand Down

0 comments on commit f7fd60a

Please sign in to comment.