Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Gmail API Support #421

Merged
merged 24 commits into from
Jul 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
47822e7
service
andris9 Jun 18, 2024
43072f9
Merge branch 'master' into gmail-api-support
andris9 Jun 18, 2024
4f8a280
OAuth app tweaks
andris9 Jun 21, 2024
f981e08
update
andris9 Jun 24, 2024
9c2e178
Create webhook topic and grant access to Gmail publisher
andris9 Jun 25, 2024
f3ac71a
Create and delete subscription for Gmail pubsub service
andris9 Jun 25, 2024
ad8a0f3
Better error handling for failing service oauth
andris9 Jun 26, 2024
36bb9f8
Do not allow changing base scopes for an existing app
andris9 Jun 26, 2024
f43b68a
working subscription pull for google
andris9 Jun 26, 2024
b86177b
show pubsub info on app page
andris9 Jun 26, 2024
87a9f3d
Allow to set pub sub app for oauth app
andris9 Jun 28, 2024
18d4b94
Fixed client id input field
andris9 Jun 28, 2024
4a9ea79
Receive push notifications from gmail
andris9 Jun 28, 2024
909a907
Store index of oauth2 usernames for every oauth2 app
andris9 Jun 29, 2024
076a88f
Do not expose access token for service apps
andris9 Jun 29, 2024
0b7ec5a
cahce gmail history id for oauth2 account
andris9 Jun 30, 2024
058dfe6
Receive history id notifications for an account
andris9 Jun 30, 2024
2ec7e8f
List gmail history entries for processing
andris9 Jun 30, 2024
309aa11
Automaticallt renew gmail watch
andris9 Jul 1, 2024
b1a9192
Process Seen/Unseen flags
andris9 Jul 3, 2024
56e68da
Updated deps
andris9 Jul 3, 2024
a315ba3
Added GET /outbox/queueId
andris9 Jul 3, 2024
0ea3a55
Send webhooks for updated and deleted messages
andris9 Jul 3, 2024
4811f15
First working version with new email webhooks
andris9 Jul 3, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion data/google-crawlers.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"creationTime": "2024-05-28T22:00:41.000000",
"creationTime": "2024-07-02T22:00:37.000000",
"prefixes": [
{
"ipv6Prefix": "2001:4860:4801:2008::/64"
Expand Down Expand Up @@ -55,6 +55,9 @@
{
"ipv6Prefix": "2001:4860:4801:201e::/64"
},
{
"ipv6Prefix": "2001:4860:4801:201f::/64"
},
{
"ipv6Prefix": "2001:4860:4801:2020::/64"
},
Expand Down Expand Up @@ -310,6 +313,9 @@
{
"ipv6Prefix": "2001:4860:4801:2093::/64"
},
{
"ipv4Prefix": "108.177.2.0/27"
},
{
"ipv4Prefix": "192.178.17.0/27"
},
Expand Down
53 changes: 49 additions & 4 deletions lib/account.js
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,7 @@ class Account {
switch (key) {
case 'notifyFrom':
case 'syncFrom':
case 'lastWatch':
// Date object
if (accountData[key]) {
if (accountData[key] === 'null') {
Expand Down Expand Up @@ -224,6 +225,7 @@ class Account {
// generic JSON values
case 'webhooksCustomHeaders':
case 'subconnections':
case 'watchResponse':
try {
let value = JSON.parse(accountData[key]);
if (value === null) {
Expand Down Expand Up @@ -328,6 +330,7 @@ class Account {
switch (key) {
case 'notifyFrom':
case 'syncFrom':
case 'lastWatch':
// Date object
if (accountData[key] === 'now') {
result[key] = new Date().toISOString();
Expand Down Expand Up @@ -362,6 +365,7 @@ class Account {
// generic JSON values
case 'subconnections':
case 'webhooksCustomHeaders':
case 'watchResponse':
try {
result[key] = JSON.stringify(accountData[key]);
} catch (err) {
Expand Down Expand Up @@ -523,7 +527,7 @@ class Account {
async update(accountData) {
let oldAccountData = await this.loadAccountData(accountData.account);

if (accountData.oauth2 && accountData.oauth2.provider) {
if (accountData.oauth2?.provider) {
// check if this OAuth2 provider exists
let oauth2App = await oauth2Apps.get(accountData.oauth2.provider);
if (!oauth2App) {
Expand All @@ -536,9 +540,9 @@ class Account {
let removeProvider;
let addProvider;

if (accountData.oauth2 && accountData.oauth2.provider) {
if (accountData.oauth2?.provider) {
addProvider = accountData.oauth2.provider;
if (oldAccountData.oauth2 && oldAccountData.oauth2.provider && oldAccountData.oauth2.provider !== accountData.oauth2.provider) {
if (oldAccountData.oauth2?.provider && oldAccountData.oauth2.provider !== accountData.oauth2.provider) {
removeProvider = oldAccountData.oauth2.provider;
}
}
Expand Down Expand Up @@ -566,10 +570,25 @@ class Account {

if (addProvider && !LEGACY_KEYS.includes(addProvider)) {
pipeline = pipeline.sadd(`${REDIS_PREFIX}oapp:a:${addProvider}`, this.account);
if (accountData.oauth2?.auth?.user) {
// check if already exists
let existingAppBinding = await this.redis.hget(`${REDIS_PREFIX}oapp:h:${accountData.oauth2.provider}`, accountData.oauth2.auth?.user);
if (existingAppBinding && existingAppBinding !== this.account) {
let message = 'Another account for the same OAuth2 user already exists';
let error = Boom.boomify(new Error(message), { statusCode: 400 });
error.output.payload.code = 'AccountAlreadyExists';
error.output.payload.existingAccount = existingAppBinding;
throw error;
}
pipeline = pipeline.hset(`${REDIS_PREFIX}oapp:h:${addProvider}`, accountData.oauth2?.auth?.user, this.account);
}
}

if (removeProvider) {
pipeline = pipeline.srem(`${REDIS_PREFIX}oapp:a:${removeProvider}`, this.account);
if (oldAccountData.oauth2?.auth?.user) {
pipeline = pipeline.hdel(`${REDIS_PREFIX}oapp:h:${removeProvider}`, oldAccountData.oauth2?.auth?.user);
}
}

let [[err, result]] = await pipeline.exec();
Expand Down Expand Up @@ -680,6 +699,18 @@ class Account {

if (accountData.oauth2 && accountData.oauth2.provider) {
pipeline = pipeline.sadd(`${REDIS_PREFIX}oapp:a:${accountData.oauth2.provider}`, this.account);
if (accountData.oauth2.auth?.user) {
// check if already exists
let existingAppBinding = await this.redis.hget(`${REDIS_PREFIX}oapp:h:${accountData.oauth2.provider}`, accountData.oauth2.auth?.user);
if (existingAppBinding && existingAppBinding !== this.account) {
let message = 'Another account for the same OAuth2 user already exists';
let error = Boom.boomify(new Error(message), { statusCode: 400 });
error.output.payload.code = 'AccountAlreadyExists';
error.output.payload.existingAccount = existingAppBinding;
throw error;
}
pipeline = pipeline.hset(`${REDIS_PREFIX}oapp:h:${accountData.oauth2.provider}`, accountData.oauth2.auth?.user, this.account);
}
}

let result = await pipeline.exec();
Expand All @@ -694,6 +725,17 @@ class Account {
if (result[0][1] && result[0][1].account) {
// existing user
state = 'existing';

try {
let oldAccountData = this.unserializeAccountData(result[0][1]);
if (oldAccountData?.oauth2?.provider && oldAccountData?.oauth2?.auth?.user && oldAccountData.oauth2.provider !== accountData.oauth2?.provider) {
// remove previous entry if provider was updated
await this.redis.hdel(`${REDIS_PREFIX}oapp:h:${oldAccountData.oauth2.provider}`, oldAccountData.oauth2.auth?.user);
}
} catch (err) {
// ignore
}

await this.call({
cmd: 'update',
account: this.account,
Expand Down Expand Up @@ -737,8 +779,11 @@ class Account {
.del(`${REDIS_PREFIX}tpl:${this.account}:i`) // stored templates index
.del(`${REDIS_PREFIX}tpl:${this.account}:c`); // stored templates index

if (accountData.oauth2 && accountData.oauth2.provider) {
if (accountData.oauth2?.provider) {
pipeline = pipeline.srem(`${REDIS_PREFIX}oapp:a:${accountData.oauth2.provider}`, this.account);
if (accountData.oauth2?.auth?.user) {
pipeline = pipeline.hdel(`${REDIS_PREFIX}oapp:h:${accountData.oauth2.provider}`, accountData.oauth2.auth?.user);
}
}

let result = await pipeline.exec();
Expand Down
4 changes: 4 additions & 0 deletions lib/api-client/base-client.js
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,10 @@ class BaseClient {
return null;
}

async close() {
return null;
}

async delete() {
return null;
}
Expand Down
Loading
Loading