drive: add scope configuration and root folder selection

This allows:

  * appdata access - Fixes #1799
  * access to backup and sync folders - Fixes #1773
  * drives.file access - Fixes #2000
  * read only access - Fixes #337
This commit is contained in:
Nick Craig-Wood 2018-01-23 13:36:20 +00:00
parent f622017539
commit a4fe2455ed
2 changed files with 147 additions and 35 deletions

View File

@ -47,6 +47,8 @@ const (
timeFormatOut = "2006-01-02T15:04:05.000000000Z07:00" timeFormatOut = "2006-01-02T15:04:05.000000000Z07:00"
minSleep = 10 * time.Millisecond minSleep = 10 * time.Millisecond
defaultExtensions = "docx,xlsx,pptx,svg" defaultExtensions = "docx,xlsx,pptx,svg"
scopePrefix = "https://www.googleapis.com/auth/"
defaultScope = "drive"
) )
// Globals // Globals
@ -65,7 +67,7 @@ var (
driveUploadCutoff = chunkSize driveUploadCutoff = chunkSize
// Description of how to auth for this app // Description of how to auth for this app
driveConfig = &oauth2.Config{ driveConfig = &oauth2.Config{
Scopes: []string{"https://www.googleapis.com/auth/drive"}, Scopes: []string{scopePrefix + "drive"},
Endpoint: google.Endpoint, Endpoint: google.Endpoint,
ClientID: rcloneClientID, ClientID: rcloneClientID,
ClientSecret: obscure.MustReveal(rcloneEncryptedClientSecret), ClientSecret: obscure.MustReveal(rcloneEncryptedClientSecret),
@ -105,6 +107,19 @@ func init() {
NewFs: NewFs, NewFs: NewFs,
Config: func(name string) { Config: func(name string) {
var err error var err error
// Fill in the scopes
scope := config.FileGet(name, "scope")
if scope == "" {
scope = defaultScope
}
driveConfig.Scopes = nil
for _, scope := range strings.Split(scope, ",") {
driveConfig.Scopes = append(driveConfig.Scopes, scopePrefix+strings.TrimSpace(scope))
// Set the root_folder_id if using drive.appfolder
if scope == "drive.appfolder" {
config.FileSet(name, "root_folder_id", "appDataFolder")
}
}
if config.FileGet(name, "service_account_file") == "" { if config.FileGet(name, "service_account_file") == "" {
err = oauthutil.Config("drive", name, driveConfig) err = oauthutil.Config("drive", name, driveConfig)
if err != nil { if err != nil {
@ -122,9 +137,31 @@ func init() {
}, { }, {
Name: config.ConfigClientSecret, Name: config.ConfigClientSecret,
Help: "Google Application Client Secret - leave blank normally.", Help: "Google Application Client Secret - leave blank normally.",
}, {
Name: "scope",
Help: "Scope that rclone should use when requesting access from drive.",
Examples: []fs.OptionExample{{
Value: "drive",
Help: "Full access all files, excluding Application Data Folder.",
}, {
Value: "drive.readonly",
Help: "Read-only access to file metadata and file contents.",
}, {
Value: "drive.file",
Help: "Access to files created by rclone only.\nThese are visible in the drive website.\nFile authorization is revoked when the user deauthorizes the app.",
}, {
Value: "drive.appfolder",
Help: "Allows read and write access to the Application Data folder.\nThis is not visible in the drive website.",
}, {
Value: "drive.metadata.readonly",
Help: "Allows read-only access to file metadata but\ndoes not allow any access to read or download file content.",
}},
}, {
Name: "root_folder_id",
Help: "ID of the root folder - leave blank normally. Fill in to access Backup and Sync folders.",
}, { }, {
Name: "service_account_file", Name: "service_account_file",
Help: "Service Account Credentials JSON file path - needed only if you want use SA instead of interactive login.", Help: "Service Account Credentials JSON file path - leave blank normally.\nNeeded only if you want use SA instead of interactive login.",
}}, }},
}) })
flags.VarP(&driveUploadCutoff, "drive-upload-cutoff", "", "Cutoff for switching to chunked upload") flags.VarP(&driveUploadCutoff, "drive-upload-cutoff", "", "Cutoff for switching to chunked upload")
@ -263,11 +300,11 @@ func (f *Fs) list(dirID string, title string, directoriesOnly bool, filesOnly bo
} }
list := f.svc.Files.List() list := f.svc.Files.List()
if len(query) > 0 { if len(query) > 0 {
list = list.Q(strings.Join(query, " and ")) list.Q(strings.Join(query, " and "))
// fmt.Printf("list Query = %q\n", query) // fmt.Printf("list Query = %q\n", query)
} }
if *driveListChunk > 0 { if *driveListChunk > 0 {
list = list.PageSize(*driveListChunk) list.PageSize(*driveListChunk)
} }
if f.isTeamDrive { if f.isTeamDrive {
list.TeamDriveId(f.teamDriveID) list.TeamDriveId(f.teamDriveID)
@ -275,6 +312,10 @@ func (f *Fs) list(dirID string, title string, directoriesOnly bool, filesOnly bo
list.IncludeTeamDriveItems(true) list.IncludeTeamDriveItems(true)
list.Corpora("teamDrive") list.Corpora("teamDrive")
} }
// If using appDataFolder then need to add Spaces
if f.rootFolderID == "appDataFolder" {
list.Spaces("appDataFolder")
}
var fields = partialFields var fields = partialFields
@ -482,6 +523,11 @@ func NewFs(name, path string) (fs.Fs, error) {
f.rootFolderID = "root" f.rootFolderID = "root"
} }
// override root folder if set in the config
if rootID := config.FileGet(name, "root_folder_id"); rootID != "" {
f.rootFolderID = rootID
}
f.dirCache = dircache.New(root, f.rootFolderID, f) f.dirCache = dircache.New(root, f.rootFolderID, f)
var about *drive.About var about *drive.About

View File

@ -32,39 +32,34 @@ n/r/c/s/q> n
name> remote name> remote
Type of storage to configure. Type of storage to configure.
Choose a number from below, or type in your own value Choose a number from below, or type in your own value
1 / Amazon Drive [snip]
\ "amazon cloud drive" 10 / Google Drive
2 / Amazon S3 (also Dreamhost, Ceph, Minio)
\ "s3"
3 / Backblaze B2
\ "b2"
4 / Dropbox
\ "dropbox"
5 / Encrypt/Decrypt a remote
\ "crypt"
6 / FTP Connection
\ "ftp"
7 / Google Cloud Storage (this is not Google Drive)
\ "google cloud storage"
8 / Google Drive
\ "drive" \ "drive"
9 / Hubic [snip]
\ "hubic" Storage> drive
10 / Local Disk
\ "local"
11 / Microsoft OneDrive
\ "onedrive"
12 / Openstack Swift (Rackspace Cloud Files, Memset Memstore, OVH)
\ "swift"
13 / SSH/SFTP Connection
\ "sftp"
14 / Yandex Disk
\ "yandex"
Storage> 8
Google Application Client Id - leave blank normally. Google Application Client Id - leave blank normally.
client_id> client_id>
Google Application Client Secret - leave blank normally. Google Application Client Secret - leave blank normally.
client_secret> client_secret>
Scope that rclone should use when requesting access from drive.
Choose a number from below, or type in your own value
1 / Full access all files, excluding Application Data Folder.
\ "drive"
2 / Read-only access to file metadata and file contents.
\ "drive.readonly"
/ Access to files created by rclone only.
3 | These are visible in the drive website.
| File authorization is revoked when the user deauthorizes the app.
\ "drive.file"
/ Allows read and write access to the Application Data folder.
4 | This is not visible in the drive website.
\ "drive.appfolder"
/ Allows read-only access to file metadata but
5 | does not allow any access to read or download file content.
\ "drive.metadata.readonly"
scope> 1
ID of the root folder - leave blank normally. Fill in to access Backup and Sync folders.
root_folder_id>
Service Account Credentials JSON file path - needed only if you want use SA instead of interactive login. Service Account Credentials JSON file path - needed only if you want use SA instead of interactive login.
service_account_file> service_account_file>
Remote config Remote config
@ -84,9 +79,12 @@ n) No
y/n> n y/n> n
-------------------- --------------------
[remote] [remote]
client_id = client_id =
client_secret = client_secret =
token = {"AccessToken":"xxxx.x.xxxxx_xxxxxxxxxxx_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx","RefreshToken":"1/xxxxxxxxxxxxxxxx_xxxxxxxxxxxxxxxxxxxxxxxxxx","Expiry":"2014-03-16T13:57:58.955387075Z","Extra":null} scope = drive
root_folder_id =
service_account_file =
token = {"access_token":"XXX","token_type":"Bearer","refresh_token":"XXX","expiry":"2014-03-16T13:57:58.955387075Z"}
-------------------- --------------------
y) Yes this is OK y) Yes this is OK
e) Edit this remote e) Edit this remote
@ -115,6 +113,74 @@ To copy a local directory to a drive directory called backup
rclone copy /home/source remote:backup rclone copy /home/source remote:backup
### Scopes ###
Rclone allows you to select which scope you would like for rclone to
use. This changes what type of token is granted to rclone. [The
scopes are defined
here.](https://developers.google.com/drive/v3/web/about-auth).
The scope are
#### drive ####
This is the default scope and allows full access to all files, except
for the Application Data Folder (see below).
Choose this one if you aren't sure.
#### drive.readonly ####
This allows read only access to all files. Files may be listed and
downloaded but not uploaded, renamed or deleted.
#### drive.file ####
With this scope rclone can read/view/modify only those files and
folders it creates.
So if you uploaded files to drive via the web interface (or any other
means) they will not be visible to rclone.
This can be useful if you are using rclone to backup data and you want
to be sure confidential data on your drive is not visible to rclone.
Files created with this scope are visible in the web interface.
#### drive.appfolder ####
This gives rclone its own private area to store files. Rclone will
not be able to see any other files on your drive and you won't be able
to see rclone's files from the web interface either.
#### drive.metadata.readonly ####
This allows read only access to file names only. It does not allow
rclone to download or upload data, or rename or delete files or
directories.
### Root folder ID ###
You can set the `root_folder_id` for rclone. This is the directory
that rclone considers to be a the root of your drive. Normally you
will leave this blank and rclone will determine the correct root to
use itself.
However you can set this to restrict rclone to a specific folder or to
access the Backup and Sync "Computers" Folders/Files. In order to do
this you will have to find the Folder ID of the folder you wish rclone
to display. This will be the last segment of the URL when you open
the folder. So if the folder/computer backup you want to show looks
like
`https://drive.google.com/drive/folders/1XyfxxxxxxxxxxxxxxxxxxxxxxxxxKHCh`
in the browser, then you use `1XyfxxxxxxxxxxxxxxxxxxxxxxxxxKHCh` as
the `root_folder_id` in the config.
**NB** the "Computers" Folders seem to be read only.
There doesn't appear to be an API to discover the folder IDs of the
"Computers" tab - please contact us if you know otherwise!
### Service Account support ### ### Service Account support ###
You can set up rclone with Google Drive in an unattended mode, You can set up rclone with Google Drive in an unattended mode,