-
Notifications
You must be signed in to change notification settings - Fork 91
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
b753be4
commit 74686be
Showing
21 changed files
with
413 additions
and
823 deletions.
There are no files selected for viewing
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,57 +1,25 @@ | ||
Fix, I have confirmed that the uploader of the file, regardless of the owner of the folder into which it is uploaded, pays the storage 'cost' for the file. To demonstate this I used two google drive accounts ([email protected] and [email protected]) | ||
# Google Drive Client for Blot | ||
|
||
I created a shared folder in [email protected], then shared it with [email protected]. I uploaded a file into it using [email protected]'s account. The storage usage for [email protected] went up, but [email protected]'s storage usage did not. | ||
This repository contains the code for Blot’s Google Drive Client, designed to handle all interactions with Google Drive for the Blot blogging platform. The client is responsible for managing shared folders, syncing changes, and facilitating smooth integration between Blot and Google Drive. | ||
|
||
--- | ||
There are two 'apps', one external which requests the user's email address through the OAUTH flow. | ||
The other is a 'service account' which has access to a Drive folder created by [email protected] | ||
|
||
The service account creates a new site folder inside the Sites folder and then shares it with the user's email. I created | ||
|
||
Add new redirect URIs here: | ||
https://console.cloud.google.com/apis/credentials?project=quickstart-1585441405190 | ||
## How It Works | ||
1. User Authentication: | ||
Users log in via Blot’s external app, which captures their Google email address. | ||
2. Folder Creation and Sharing: | ||
The internal Google Drive Client uses the captured email to: | ||
• Create a folder in Blot’s Google Drive account. | ||
• Share the folder with the user (role=editor). | ||
3. Change Tracking and Syncing: | ||
• Monitor the shared folder for changes using the Google Drive API. | ||
• Sync updates, including file uploads, edits, and deletions, to Blot’s server. | ||
|
||
--- | ||
|
||
Questions | ||
- is there an overhead to creating the oauth2 client each time? can we safely reuse it? | ||
- is it possible to restrict Blot's access to a single folder in the google drive? | ||
- it doesn't seem like it is | ||
|
||
I believe we will need this API for drive changes: | ||
https://developers.google.com/drive/activity/v2 | ||
|
||
Since the changes.list api doesn't return rename events, it seems. | ||
|
||
The webhooks are now tunnelled through webhooks.blot.im using clients/webhooks.js | ||
|
||
Test server | ||
``` | ||
http://localhost:8822/clients/googledrive/authenticate | ||
``` | ||
|
||
Resources: | ||
|
||
[Verify domain ownership](https://search.google.com/search-console/settings?resource_id=sc-domain%3Ablot.im) | ||
|
||
[Domain verification for API use](https://console.cloud.google.com/apis/credentials/domainverification?organizationId=683828060430&project=quickstart-1585441405190) | ||
|
||
[Console for redirect URIs](https://console.cloud.google.com/apis/credentials/oauthclient/32772360147-pnntpgr8pjnlem4m6s1perkju3ghce3b.apps.googleusercontent.com?project=quickstart-1585441405190&pli=1) | ||
|
||
[Console for managing API permissions](https://console.developers.google.com/apis/credentials/oauthclient/32772360147-pnntpgr8pjnlem4m6s1perkju3ghce3b.apps.googleusercontent.com?project=quickstart-1585441405190) | ||
|
||
[Downloading files google drive](https://stackoverflow.com/questions/62476413/google-drive-api-downloading-file-nodejs) | ||
|
||
[Downloading files google drive](https://developers.google.com/drive/api/v3/manage-downloads) | ||
|
||
[Link to remove connection during testing](https://myaccount.google.com/permissions?pli=1) | ||
|
||
Documentation: | ||
|
||
[nodejs-client authentication-and-authorization](https://github.com/googleapis/google-api-nodejs-client#authentication-and-authorization) | ||
|
||
[quickstart](https://developers.google.com/drive/api/v3/quickstart/nodejs) | ||
SHould we ask the user to share a folder with our email? This was it's a 'true' folder and doesn't show up in 'shared with me'. | ||
|
||
Actions to test: | ||
- Mass rename -> mass move | ||
- Mass move -> mass rename | ||
- Delete -> Restore -> Delete | ||
- Move file from outside folder into folder | ||
- Move file from inside folder out of folder | ||
How is storage usage affected by 'service accounts'? |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,73 +1,39 @@ | ||
const config = require("config"); | ||
const database = require("./database"); | ||
const google = require("googleapis").google; | ||
const Blog = require("models/blog"); | ||
const establishSyncLock = require("./util/establishSyncLock"); | ||
const database = require("./database"); | ||
const createDriveClient = require("./util/createDriveClient"); | ||
const debug = require("debug")("blot:clients:google-drive"); | ||
|
||
async function disconnect(blogID, callback) { | ||
let done; | ||
|
||
try { | ||
let lock = await establishSyncLock(blogID); | ||
done = lock.done; | ||
} catch (err) { | ||
return callback(err); | ||
} | ||
|
||
debug("getting account info"); | ||
const account = await database.getAccount(blogID); | ||
|
||
if (account && account.access_token && account.refresh_token) { | ||
const canRevoke = await database.canRevoke(account.permissionId); | ||
const auth = new google.auth.OAuth2( | ||
config.google.drive.key, | ||
config.google.drive.secret | ||
); | ||
|
||
auth.setCredentials({ | ||
refresh_token: account.refresh_token, | ||
access_token: account.access_token, | ||
}); | ||
|
||
if (account.channel) { | ||
try { | ||
debug("attempting to stop listening to webhooks"); | ||
const drive = google.drive({ version: "v3", auth }); | ||
await drive.channels.stop({ | ||
requestBody: account.channel, | ||
}); | ||
debug("stop listening to webhooks successfully"); | ||
} catch (e) { | ||
debug("failed to stop webhooks but no big deal:", e.message); | ||
debug("it will expire automatically"); | ||
} | ||
} | ||
|
||
// We need to preserve Blot's access to this Google | ||
// Drive account if another blog uses it. Unfortunately | ||
// it seems impossible to simple revoke one blog's access | ||
// other blogs connected to the account lose access too. | ||
if (canRevoke) { | ||
try { | ||
debug("Trying to revoke Google API credentials"); | ||
// destroys the oauth2Client's active | ||
// refresh_token and access_token | ||
await auth.revokeCredentials(); | ||
} catch (e) { | ||
debug("Failed to revoke but token should expire naturally", e.message); | ||
} | ||
} | ||
} | ||
|
||
debug("dropping blog from database"); | ||
await database.dropAccount(blogID); | ||
|
||
debug("resetting client setting"); | ||
Blog.set(blogID, { client: "" }, async function (err) { | ||
await done(err); | ||
callback(); | ||
}); | ||
} | ||
|
||
module.exports = disconnect; | ||
module.exports = async (blogID, callback) => { | ||
let done; | ||
|
||
try { | ||
let lock = await establishSyncLock(blogID); | ||
done = lock.done; | ||
} catch (err) { | ||
return callback(err); | ||
} | ||
|
||
const account = await database.getAccount(blogID); | ||
|
||
if (account && account.channel) { | ||
const drive = await createDriveClient(blogID); | ||
try { | ||
debug("attempting to stop listening to webhooks"); | ||
await drive.channels.stop({ | ||
requestBody: account.channel, | ||
}); | ||
debug("stop listening to webhooks successfully"); | ||
} catch (e) { | ||
debug("failed to stop webhooks but no big deal:", e.message); | ||
debug("it will expire automatically"); | ||
} | ||
} | ||
|
||
await database.dropAccount(blogID); | ||
|
||
Blog.set(blogID, { client: "" }, async function (err) { | ||
await done(err); | ||
callback(); | ||
}); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.