Skip to content

Commit

Permalink
CLI support for custom credentials for OneDrive (client_id/client_sec…
Browse files Browse the repository at this point in the history
…ret)
  • Loading branch information
sevimo123 committed Jul 23, 2022
1 parent 54952ce commit 238ef63
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 11 deletions.
43 changes: 35 additions & 8 deletions src/duplicacy_oneclient.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
package duplicacy

import (
"context"
"bytes"
"encoding/json"
"fmt"
Expand Down Expand Up @@ -39,6 +40,7 @@ type OneDriveClient struct {

TokenFile string
Token *oauth2.Token
OAConfig *oauth2.Config
TokenLock *sync.Mutex

IsConnected bool
Expand All @@ -49,7 +51,7 @@ type OneDriveClient struct {
APIURL string
}

func NewOneDriveClient(tokenFile string, isBusiness bool) (*OneDriveClient, error) {
func NewOneDriveClient(tokenFile string, isBusiness bool, client_id string, client_secret string) (*OneDriveClient, error) {

description, err := ioutil.ReadFile(tokenFile)
if err != nil {
Expand All @@ -65,10 +67,25 @@ func NewOneDriveClient(tokenFile string, isBusiness bool) (*OneDriveClient, erro
HTTPClient: http.DefaultClient,
TokenFile: tokenFile,
Token: token,
OAConfig: nil,
TokenLock: &sync.Mutex{},
IsBusiness: isBusiness,
}

if (client_id != "") {
oneOauthConfig := oauth2.Config{
ClientID: client_id,
ClientSecret: client_secret,
Scopes: []string{"Files.ReadWrite", "offline_access"},
Endpoint: oauth2.Endpoint{
AuthURL: "https://login.microsoftonline.com/common/oauth2/v2.0/authorize",
TokenURL: "https://login.microsoftonline.com/common/oauth2/v2.0/token",
},
}

client.OAConfig = &oneOauthConfig
}

if isBusiness {
client.RefreshTokenURL = "https://duplicacy.com/odb_refresh"
client.APIURL = "https://graph.microsoft.com/v1.0/me"
Expand Down Expand Up @@ -218,15 +235,25 @@ func (client *OneDriveClient) RefreshToken(force bool) (err error) {
return nil
}

readCloser, _, err := client.call(client.RefreshTokenURL, "POST", client.Token, "")
if err != nil {
return fmt.Errorf("failed to refresh the access token: %v", err)
}
if (client.OAConfig == nil) {
readCloser, _, err := client.call(client.RefreshTokenURL, "POST", client.Token, "")
if err != nil {
return fmt.Errorf("failed to refresh the access token: %v", err)
}

defer readCloser.Close()
defer readCloser.Close()

if err = json.NewDecoder(readCloser).Decode(client.Token); err != nil {
return err
if err = json.NewDecoder(readCloser).Decode(client.Token); err != nil {
return err
}
} else {
ctx := context.Background()
tokenSource := client.OAConfig.TokenSource(ctx, client.Token)
token, err := tokenSource.Token()
if err != nil {
return fmt.Errorf("failed to refresh the access token: %v", err)
}
client.Token = token
}

description, err := json.Marshal(client.Token)
Expand Down
4 changes: 2 additions & 2 deletions src/duplicacy_onestorage.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,13 @@ type OneDriveStorage struct {
}

// CreateOneDriveStorage creates an OneDrive storage object.
func CreateOneDriveStorage(tokenFile string, isBusiness bool, storagePath string, threads int) (storage *OneDriveStorage, err error) {
func CreateOneDriveStorage(tokenFile string, isBusiness bool, storagePath string, threads int, client_id string, client_secret string) (storage *OneDriveStorage, err error) {

for len(storagePath) > 0 && storagePath[len(storagePath)-1] == '/' {
storagePath = storagePath[:len(storagePath)-1]
}

client, err := NewOneDriveClient(tokenFile, isBusiness)
client, err := NewOneDriveClient(tokenFile, isBusiness, client_id, client_secret)
if err != nil {
return nil, err
}
Expand Down
18 changes: 17 additions & 1 deletion src/duplicacy_storage.go
Original file line number Diff line number Diff line change
Expand Up @@ -647,12 +647,28 @@ func CreateStorage(preference Preference, resetPassword bool, threads int) (stor
storagePath := matched[3] + matched[4]
prompt := fmt.Sprintf("Enter the path of the OneDrive token file (downloadable from https://duplicacy.com/one_start):")
tokenFile := GetPassword(preference, matched[1] + "_token", prompt, true, resetPassword)
oneDriveStorage, err := CreateOneDriveStorage(tokenFile, matched[1] == "odb", storagePath, threads)

// client_id, just like tokenFile, can be stored in preferences
//prompt = fmt.Sprintf("Enter client_id for custom Azure app (if empty will use duplicacy.com one):")
client_id := GetPasswordFromPreference(preference, matched[1] + "_client_id")
client_secret := ""

if client_id != "" {
// client_secret should go into keyring
prompt = fmt.Sprintf("Enter client_secret for custom Azure app (if empty will use duplicacy.com one):")
client_secret = GetPassword(preference, matched[1] + "_client_secret", prompt, true, resetPassword)
}

oneDriveStorage, err := CreateOneDriveStorage(tokenFile, matched[1] == "odb", storagePath, threads, client_id, client_secret)
if err != nil {
LOG_ERROR("STORAGE_CREATE", "Failed to load the OneDrive storage at %s: %v", storageURL, err)
return nil
}

SavePassword(preference, matched[1] + "_token", tokenFile)
if client_id != "" {
SavePassword(preference, matched[1] + "_client_secret", client_secret)
}
return oneDriveStorage
} else if matched[1] == "hubic" {
storagePath := matched[3] + matched[4]
Expand Down

0 comments on commit 238ef63

Please sign in to comment.