From 29808c905cea9e365e074dbdd95889b825b1f60e Mon Sep 17 00:00:00 2001 From: abraunegg Date: Tue, 4 Dec 2018 10:59:23 +1100 Subject: [PATCH] Implement --get-O365-drive-id to get correct SharePoint Shared Library (Issue #248) (#260) * Implement --get-O365-drive-id to return the correct drive_id of a SharePoint Shared Library to use for syncing that repository --- README.Office365.md | 74 +++++---------------------------------------- README.md | 5 +-- onedrive.1.in | 5 ++- src/main.d | 10 +++++- src/onedrive.d | 23 ++++++++++++++ src/sync.d | 33 ++++++++++++++++++++ 6 files changed, 80 insertions(+), 70 deletions(-) diff --git a/README.Office365.md b/README.Office365.md index d647206d..6ed0fb9b 100644 --- a/README.Office365.md +++ b/README.Office365.md @@ -1,79 +1,21 @@ # Show how to access a Sharepoint group drive in Office 365 business or education ## Obtaining the Sharepoint Site Details - When we click "sync" in a Sharepoint groups Documents page we get an "odopen" URL, for example: - ``` - odopen://sync?userId=97858aa6%2Dcd6a%2D4025%2Da6ee%2D29ba80bcbec5&siteId=%7B0936e7d2%2D1285%2D4c54%2D81f9%2D55e9c8b8613b%7D&webId=%7B345db3b7%2D1ebb%2D484f%2D85e3%2D31c785278051%7D&webTitle=FFCCTT%5FIET&listId=%7BA3913FAC%2D26F8%2D4436%2DA9F6%2DAA6B44776343%7D&listTitle=Documentos&userEmail=georg%2Elehner%40ucan%2Eedu%2Eni&listTemplateTypeId=101&webUrl=https%3A%2F%2Fucanedu%2Esharepoint%2Ecom%2Fsites%2FFFCCTT%5FIET&webLogoUrl=%2Fsites%2FFFCCTT%5FIET%2F%5Fapi%2FGroupService%2FGetGroupImage%3Fid%3D%270e6466dc%2D1d90%2D41b0%2D9c9d%2Df6a818721435%27%26hash%3D636549326262064339&isSiteAdmin=1&webTemplate=64&onPrem=0&scope=OPENLIST - ``` - -When we decode this URL we get the following: - +1. Login to OneDrive and under 'Shared Libraries' obtain the shared library name +2. Run the following command using the 'onedrive' client ``` - userId=97858aa6-cd6a-4025-a6ee-29ba80bcbec5 - siteId={0936e7d2-1285-4c54-81f9-55e9c8b8613b} - webId={345db3b7-1ebb-484f-85e3-31c785278051} - webTitle=FFCCTT_IET - listId={A3913FAC-26F8-4436-A9F6-AA6B44776343} - listTitle=Documentos - userEmail=georg.lehner@ucan.edu.ni - listTemplateTypeId=101 - webUrl=https://ucanedu.sharepoint.com/sites/FFCCTT_IET - webLogoUrl=/sites/FFCCTT_IET/_api/GroupService/GetGroupImage?id='0e6466dc-1d90-41b0-9c9d-f6a818721435'&hash=636549326262064339 - isSiteAdmin=1 - webTemplate=64 - onPrem=0 - scope=OPENLIST +onedrive --get-O365-drive-id '' ``` - -In the following we refer to these parameters with e.g. $userId - wherever there are enclosing braces {} you have to strip them off. - -## Obtaining the Authorization Token - -To get the 'authorization bearer', run the following command: -``` -onedrive --monitor --print-token -``` - -This will print out something like the following: +3. This will return the following: ``` Initializing the Synchronization Engine ... -New access token: bearer EwBYA8l6......T51Ag== -Initializing monitor ... -OneDrive monitor interval (seconds): 45 +Office 365 Library Name: ab-github-odtest +drive_id: b!6H.....l7vVxU5 ``` -Everything after 'New access token: bearer' is your authorization token. - -## Obtaining the Drive ID -To sync an Office365 / Business Shared Folder we need the Drive ID for that shared folder. - -1. Get site drive-id with: -``` -https://graph.microsoft.com/v1.0/sites/$host,$SiteId,$webId/lists/$listId/drive -``` -**Example:** -``` -curl -i 'https://graph.microsoft.com/v1.0/sites/ucanedu.sharepoint.com,0936e7d2-1285-4c54-81f9-55e9c8b8613b,345db3b7-1ebb-484f-85e3-31c785278051/lists/A3913FAC-26F8-4436-A9F6-AA6B44776343/drive' -H "Authorization: bearer " -``` -where $host is the hostname in $webUrl. This should return the following response which is the drive id: - -b!0uc2CYUSVEyB-VXpyLhhO7ezXTS7Hk9IheMxx4UngFGsP5Gj-CY2RKn2qmtEd2ND - -2. Get root folder id via drive-id -``` -GET https://graph.microsoft.com/v1.0/drives/$drive-id/root -``` -**Example:** -``` -curl -i 'https://graph.microsoft.com/v1.0/drives/b!0uc2CYUSVEyB-VXpyLhhO7ezXTS7Hk9IheMxx4UngFGsP5Gj-CY2RKn2qmtEd2ND/root' -H "Authorization: bearer " -``` - -This should return the following response: - -016SJBHDN6Y2GOVW7725BZO354PWSELRRZ ## Configuring the onedrive client -Once you have obtained the 'drive id', add to your 'onedrive' configuration file (`~/.config/onedrive/config`)the following: +Once you have obtained the 'drive_id' above, add to your 'onedrive' configuration file (`~/.config/onedrive/config`)the following: ``` drive_id = "insert the drive id from above here" ``` -The OneDrive client will now sync this shared 'drive id' +The OneDrive client will now sync this SharePoint shared library to your local system. diff --git a/README.md b/README.md index 392f376f..5e5c7839 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ * Resumable uploads * Support OneDrive for Business (part of Office 365) * Shared folders (OneDrive Personal) -* SharePoint / Office 365 Group Drives (refer to README.Office365.md to configure) +* SharePoint / Office 365 Shared Libraries (refer to README.Office365.md to configure) ### What's missing: * While local changes are uploaded right away, remote changes are delayed @@ -39,7 +39,7 @@ curl -fsS https://dlang.org/install.sh | bash -s dmd ### Dependencies: Debian - i386 / i686 **Note:** Validated with `Linux debian-i386 4.9.0-7-686-pae #1 SMP Debian 4.9.110-1 (2018-07-05) i686 GNU/Linux` and LDC - the LLVM D compiler (1.8.0). -First install development dependancies as per below: +First install development dependencies as per below: ``` sudo apt install build-essential sudo apt install libcurl4-openssl-dev @@ -423,6 +423,7 @@ no option No sync and exit -d --download-only Only download remote changes --disable-upload-validation Disable upload validation when uploading to OneDrive --enable-logging Enable client activity to a separate log file + --get-O365-drive-id Query and return the Office 365 Drive ID for a given Office 365 SharePoint Shared Library --local-first Synchronize from the local directory source first, before downloading changes from OneDrive. --logout Logout the current user -m --monitor Keep monitoring for local and remote changes diff --git a/onedrive.1.in b/onedrive.1.in index b6366259..f491ed40 100644 --- a/onedrive.1.in +++ b/onedrive.1.in @@ -33,6 +33,9 @@ Disable upload validation when uploading to OneDrive \fB\-\-enable\-logging\fP Enable client activity to a separate log file .TP +\fB\-\-get\-O365\-drive\-id\fP +Query and return the Office 365 Drive ID for a given Office 365 SharePoint Shared Library +.TP \fB\-\-local\-first\fP Synchronize from the local directory source first, before downloading changes from OneDrive. .TP @@ -192,4 +195,4 @@ where \fB%username%\fP represents the user who ran the client. Further examples and documentation is available in \f[C]@DOCDIR@/README.md\f[] - +\f[C]@DOCDIR@/README.Office365.md\f[] diff --git a/src/main.d b/src/main.d index 138a56e5..601c0967 100644 --- a/src/main.d +++ b/src/main.d @@ -88,6 +88,8 @@ int main(string[] args) // Does the user want to disable upload validation - https://github.com/abraunegg/onedrive/issues/205 // SharePoint will associate some metadata from the library the file is uploaded to directly in the file - thus change file size & checksums bool disableUploadValidation = false; + // SharePoint / Office 365 Shared Library name to query + string o365SharedLibraryName; try { auto opt = getopt( @@ -102,6 +104,7 @@ int main(string[] args) "download-only|d", "Only download remote changes", &downloadOnly, "disable-upload-validation", "Disable upload validation when uploading to OneDrive", &disableUploadValidation, "enable-logging", "Enable client activity to a separate log file", &enableLogFile, + "get-O365-drive-id", "Query and return the Office 365 Drive ID for a given Office 365 SharePoint Shared Library", &o365SharedLibraryName, "local-first", "Synchronize from the local directory source first, before downloading changes from OneDrive.", &localFirst, "logout", "Logout the current user", &logout, "monitor|m", "Keep monitoring for local and remote changes", &monitor, @@ -205,7 +208,7 @@ int main(string[] args) // create-directory, remove-directory, source-directory, destination-directory // are activities that dont perform a sync no error message for these items either - if (((createDirectory != "") || (removeDirectory != "")) || ((sourceDirectory != "") && (destinationDirectory != "")) ) { + if (((createDirectory != "") || (removeDirectory != "")) || ((sourceDirectory != "") && (destinationDirectory != "")) || (o365SharedLibraryName != "") ) { performSyncOK = true; } @@ -307,6 +310,11 @@ int main(string[] args) sync.renameDirectoryNoSync(sourceDirectory, destinationDirectory); } + // Are we obtaining the Office 365 Drive ID for a given Office 365 SharePoint Shared Library? + if (o365SharedLibraryName != ""){ + sync.querySiteCollectionForDriveID(o365SharedLibraryName); + } + // Are we performing a sync, resync or monitor operation? if ((synchronize) || (resync) || (monitor)) { diff --git a/src/onedrive.d b/src/onedrive.d index dd28c8b2..5ae49057 100644 --- a/src/onedrive.d +++ b/src/onedrive.d @@ -10,11 +10,18 @@ static import log; shared bool debugResponse = false; private immutable { + // Client Identifier string clientId = "22c49a0d-d21c-4792-aed1-8f163c982546"; + + // Personal & Business Queries string authUrl = "https://login.microsoftonline.com/common/oauth2/v2.0/authorize"; string redirectUrl = "https://login.microsoftonline.com/common/oauth2/nativeclient"; string tokenUrl = "https://login.microsoftonline.com/common/oauth2/v2.0/token"; string driveByIdUrl = "https://graph.microsoft.com/v1.0/drives/"; + + // Office 365 / SharePoint Queries + string siteSearchUrl = "https://graph.microsoft.com/v1.0/sites?search"; + string siteDriveUrl = "https://graph.microsoft.com/v1.0/sites/"; } private { @@ -303,6 +310,22 @@ final class OneDriveApi return get(uploadUrl, true); } + // https://docs.microsoft.com/en-us/onedrive/developer/rest-api/api/site_search?view=odsp-graph-online + JSONValue o365SiteSearch(string o365SharedLibraryName){ + checkAccessTokenExpired(); + const(char)[] url; + url = siteSearchUrl ~ "=" ~ o365SharedLibraryName; + return get(url); + } + + // https://docs.microsoft.com/en-us/onedrive/developer/rest-api/api/drive_list?view=odsp-graph-online + JSONValue o365SiteDrives(string site_id){ + checkAccessTokenExpired(); + const(char)[] url; + url = siteDriveUrl ~ site_id ~ "/drives"; + return get(url); + } + private void redeemToken(const(char)[] authCode) { const(char)[] postData = diff --git a/src/sync.d b/src/sync.d index 1e9d862f..0999e39c 100644 --- a/src/sync.d +++ b/src/sync.d @@ -1708,4 +1708,37 @@ final class SyncEngine // Make the change on OneDrive auto res = onedrive.moveByPath(sourcePath, moveData); } + + // Query Office 365 SharePoint Shared Library site to obtain it's Drive ID + void querySiteCollectionForDriveID(string o365SharedLibraryName){ + // Steps to get the ID: + // 1. Query https://graph.microsoft.com/v1.0/sites?search= with the name entered + // 2. Evaluate the response. A valid response will contain the description and the id. If the response comes back with nothing, the site name cannot be found or no access + // 3. If valid, use the returned ID and query the site drives + // https://graph.microsoft.com/v1.0/sites//drives + // 4. Display Shared Library Name & Drive ID + + string site_id; + string drive_id; + JSONValue siteQuery = onedrive.o365SiteSearch(o365SharedLibraryName); + + foreach (searchResult; siteQuery["value"].array) { + // Need an 'exclusive' match here with as entered + if (o365SharedLibraryName == searchResult["description"].str){ + // 'description' matches search request + site_id = searchResult["id"].str; + JSONValue siteDriveQuery = onedrive.o365SiteDrives(site_id); + foreach (driveResult; siteDriveQuery["value"].array) { + drive_id = driveResult["id"].str; + } + } + } + + log.log("Office 365 Library Name: ", o365SharedLibraryName); + if(drive_id != null) { + log.log("drive_id: ", drive_id); + } else { + writeln("ERROR: This site could not be found. Please check it's name and your permissions to access the site."); + } + } }