diff --git a/README.md b/README.md index c1db2a75..91e3e40c 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ cp /usr/local/etc/onedrive.conf ~/.config/onedrive/config Available options: -* `client_id` & `client_secret`: application identifiers necessary during the [authentication][2] +* `client_id`: application identifier necessary for the [authentication][2] * `sync_dir`: directory where the files will be synced * `skip_file`: any files that match this pattern will be skipped during sync * `skip_dir`: any directories that match this pattern will be skipped during sync diff --git a/onedrive.conf b/onedrive.conf index e9284bbc..ae7f2282 100644 --- a/onedrive.conf +++ b/onedrive.conf @@ -1,5 +1,4 @@ client_id = "000000004C15842F" -client_secret = "5vWj5xi6rYZM61X81Z9OyXAmjGhVS6Py" sync_dir = "~/OneDrive" skip_file = ".*|~*" skip_dir = ".*" diff --git a/src/onedrive.d b/src/onedrive.d index cf70d61d..25be0b97 100644 --- a/src/onedrive.d +++ b/src/onedrive.d @@ -6,7 +6,7 @@ import config; private immutable { string authUrl = "https://login.live.com/oauth20_authorize.srf"; - string redirectUrl = "https://login.live.com/oauth20_desktop.srf"; + string redirectUrl = "https://login.live.com/oauth20_desktop.srf"; // "urn:ietf:wg:oauth:2.0:oob"; string tokenUrl = "https://login.live.com/oauth20_token.srf"; string itemByIdUrl = "https://api.onedrive.com/v1.0/drive/items/"; string itemByPathUrl = "https://api.onedrive.com/v1.0/drive/root:/"; @@ -32,7 +32,7 @@ class OneDriveException: Exception final class OneDriveApi { - private string clientId, clientSecret; + private string clientId; private string refreshToken, accessToken; private SysTime accessTokenExpiration; /* private */ HTTP http; @@ -42,7 +42,6 @@ final class OneDriveApi this(Config cfg, bool verbose) { this.clientId = cfg.get("client_id"); - this.clientSecret = cfg.get("client_secret"); http = HTTP(); //http.verbose = verbose; } @@ -50,7 +49,7 @@ final class OneDriveApi void authorize() { import std.stdio, std.regex; - string url = authUrl ~ "?client_id=" ~ clientId ~ "&scope=wl.offline_access%20onedrive.readwrite&response_type=code&redirect_uri=" ~ redirectUrl; + string url = authUrl ~ "?client_id=" ~ clientId ~ "&scope=onedrive.readwrite%20offline_access&response_type=code&redirect_uri=" ~ redirectUrl; writeln("Authorize this app visiting:\n"); writeln(url, "\n"); @@ -72,21 +71,22 @@ final class OneDriveApi this.refreshToken = refreshToken; } - // https://dev.onedrive.com/items/view_changes.htm + // https://dev.onedrive.com/items/view_delta.htm JSONValue viewChangesById(const(char)[] id, const(char)[] statusToken) { checkAccessTokenExpired(); - char[] url = itemByIdUrl ~ id ~ "/view.changes"; + const(char)[] url = itemByIdUrl ~ id ~ "/view.delta"; + url ~= "?select=id,name,eTag,cTag,deleted,file,folder,fileSystemInfo,remoteItem,parentReference"; if (statusToken) url ~= "?token=" ~ statusToken; return get(url); } - // https://dev.onedrive.com/items/view_changes.htm + // https://dev.onedrive.com/items/view_delta.htm JSONValue viewChangesByPath(const(char)[] path, const(char)[] statusToken) { checkAccessTokenExpired(); - string url = itemByPathUrl ~ encodeComponent(path) ~ ":/view.changes"; - url ~= "?select=id,name,eTag,cTag,deleted,file,folder,fileSystemInfo,parentReference"; + string url = itemByPathUrl ~ encodeComponent(path) ~ ":/view.delta"; + url ~= "?select=id,name,eTag,cTag,deleted,file,folder,fileSystemInfo,remoteItem,parentReference"; if (statusToken) url ~= "&token=" ~ statusToken; return get(url); } @@ -99,7 +99,7 @@ final class OneDriveApi import std.file; if (exists(saveToPath)) remove(saveToPath); } - char[] url = itemByIdUrl ~ id ~ "/content?AVOverride=1"; + const(char)[] url = itemByIdUrl ~ id ~ "/content"; download(url, saveToPath); } @@ -183,15 +183,21 @@ final class OneDriveApi private void redeemToken(const(char)[] authCode) { - string postData = "client_id=" ~ clientId ~ "&redirect_uri=" ~ redirectUrl ~ "&client_secret=" ~ clientSecret; - postData ~= "&code=" ~ authCode ~ "&grant_type=authorization_code"; + const(char)[] postData = + "client_id=" ~ clientId ~ + "&redirect_uri=" ~ redirectUrl ~ + "&code=" ~ authCode ~ + "&grant_type=authorization_code"; acquireToken(postData); } private void newToken() { - string postData = "client_id=" ~ clientId ~ "&redirect_uri=" ~ redirectUrl ~ "&client_secret=" ~ clientSecret; - postData ~= "&refresh_token=" ~ refreshToken ~ "&grant_type=refresh_token"; + string postData = + "client_id=" ~ clientId ~ + "&redirect_uri=" ~ redirectUrl ~ + "&refresh_token=" ~ refreshToken ~ + "&grant_type=refresh_token"; acquireToken(postData); } diff --git a/src/sync.d b/src/sync.d index a169d0ab..ed511fc2 100644 --- a/src/sync.d +++ b/src/sync.d @@ -95,9 +95,9 @@ final class SyncEngine foreach (item; changes["value"].array) { applyDifference(item); } - statusToken = changes["@changes.token"].str; + statusToken = changes["@delta.token"].str; onStatusToken(statusToken); - } while (changes["@changes.hasMoreChanges"].type == JSON_TYPE.TRUE); + } while (("@odata.nextLink" in changes.object) !is null); } catch (ErrnoException e) { throw new SyncException(e.msg, e); } catch (FileException e) { @@ -146,11 +146,9 @@ final class SyncEngine } // compute the path of the item - string path; + string path = "."; if (parentId) { path = itemdb.computePath(parentId) ~ "/" ~ name; - } else { - path = "."; } ItemType type; @@ -181,13 +179,13 @@ final class SyncEngine } string cTag; - try { - cTag = item["cTag"].str; - } catch (JSONException e) { - // cTag is not returned if the Item is a folder - // https://dev.onedrive.com/resources/item.htm - cTag = ""; - } + try { + cTag = item["cTag"].str; + } catch (JSONException e) { + // cTag is not returned if the Item is a folder + // https://dev.onedrive.com/resources/item.htm + cTag = ""; + } string mtime = item["fileSystemInfo"]["lastModifiedDateTime"].str;