Cannot refresh oauth token in China due to GFW

It seems the ‘duplicacy.com’ is blocked in China. The backup failed because it cannot update the token:

‘’’
2020-11-26 15:52:49.532 INFO ONEDRIVE_RETRY Post https://duplicacy.com/odb_refresh: dial tcp 216.239.36.21:443: i/o timeout; retry after 857 milliseconds
‘’’

Is there any way I can deploy the site ‘odb_refresh’ locally?

Thanks

You can create service account in the google cloud, share your drive with it and have duplicacy backup using that account.

Alternatively, if you have g-suite / workspace you can grant service account access to your account and have it impersonate you. This works, but changes are not yet checked it; you would need to build from source. I’ve documented step-by-step howto here: Duplicacy backup to Google Drive with Service Account | Trinkets, Odds, and Ends

Either way will avoid need to renew tokens.

I don’t think there is a way to avoid renewing tokens for OneDrive.

@caq2qac I can share the server code that refreshes the token, but you’ll need to host it on your own site and also modify the CLI to use your own refresh url.

Thanks. Unfortunately, Google is not an option for me because Google is blocked in China.

I backup to OneDrive and it works for a while. Recently it failed because the duplicacy site is blocked in China.

Thank you. I can host it on my own site. Please share the server code that refreshes the token.

Oh, my bad. I misread odb_refresh as gcd_refresh.

Could I kindly inquire if there are any updates about this?

Do you have any updates?

Sorry about the delay. I’l try to get you a working program tomorrow.

Here is a program with the two handlers taken from the web server running duplicacy.com. It compiles but I didn’t get a chance to test it.

You’ll need to fill in your own client id and client secret.

package main

import (
    "fmt"
    "encoding/json"
    "net/http"
    "crypto/tls"

    "golang.org/x/oauth2"
    "golang.org/x/crypto/acme/autocert"
)

var (
    oneOauthConfig = oauth2.Config{
        ClientID: "",
        ClientSecret: "",
        RedirectURL:  "https://yourwebsite/one_oauth",
        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",
        },
    }
)

// OauthHandler ...
func oneOauthHandler(w http.ResponseWriter, r *http.Request) {

    token, err := oneOauthConfig.Exchange(r.Context(), r.URL.Query().Get("code"))
    if err != nil {
        http.Error(w, fmt.Sprintf("Error exchanging the code for an access token: %v", err), http.StatusInternalServerError)
        return
    }

    w.Header().Set("Content-Disposition", "attachment; filename=one-token.json")
    w.Header().Set("Content-Type", "application/json; charset=utf-8")
    if err := json.NewEncoder(w).Encode(token); err != nil {
        http.Error(w, fmt.Sprintf("Error encoding the token in JSON: %v", err), http.StatusInternalServerError)
        return
    }
}

// RefreshHandler ...
func oneRefreshHandler(w http.ResponseWriter, r *http.Request) {
    var token oauth2.Token
    defer r.Body.Close()

    if err := json.NewDecoder(r.Body).Decode(&token); err != nil {
       http.Error(w, fmt.Sprintf("Error decoding the token from the request: %v", err), http.StatusBadRequest)
       return
    }

    tokenSource := oneOauthConfig.TokenSource(r.Context(), &token)
    newToken, err := tokenSource.Token()
    if err != nil {
        http.Error(w, fmt.Sprintf("Error fetching a new token: %v", err), http.StatusBadRequest)
        return
    }

    w.Header().Set("Content-Type", "application/json; charset=utf-8")
    if err := json.NewEncoder(w).Encode(newToken); err != nil {
        http.Error(w, fmt.Sprintf("Error encoding the token in JSON: %v", err), http.StatusInternalServerError)
        return
    }
}

func main() {

    http.HandleFunc("/one_oauth", oneOauthHandler)
    http.HandleFunc("/one_refresh", oneRefreshHandler)

    certManager := autocert.Manager{
        Prompt:     autocert.AcceptTOS,
        Cache:      autocert.DirCache("certs"),
    }

    server := &http.Server{
        Addr: ":https",
        TLSConfig: &tls.Config{
            GetCertificate: certManager.GetCertificate,
        },
    }

    go func() {
        err := http.ListenAndServe(":80", certManager.HTTPHandler(nil))
        fmt.Printf("Failed to start the http server: %v\n", err)
    } ()

    err := server.ListenAndServeTLS("", "")
    if err != nil {
        fmt.Printf("Failed to start the https server: %v\n", err)
    }

}

Thank you. The code is for one_oauth and one_refresh. However, I’m using odb_oauth. Would you please provide the two handlers for odb_oauth and odb_refresh? Or they share the same oauth code and the only difference is token filename “one-token.json” or “odb-token.json”? If they share the same code, then I can modify the code myself.

I test the one_oauth and I can download the one-token.json. I use this token as odb token and it seems to work.

one_* and odb_* share the same code. It is just that their oauth2.Config objects are different.

This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.