1
0
mirror of https://github.com/rclone/rclone.git synced 2025-12-06 00:03:32 +00:00

jottacloud: added support for traditional oauth authentication also for the main service

This renames whitelabel authentication to traditional authentication and adds support for
the main Jottacloud service also here, as it can be used as an alternative to the
authentication based on personal login token for those who prefer it. Documentation
also adjusted correspondingly, and restructured the authentication section a bit more
since some of the sections that was under standard authentication in reality also
applies to the traditional authentication.
This commit is contained in:
albertony
2025-10-04 13:56:29 +02:00
parent 4510aa679a
commit 697874e399
2 changed files with 123 additions and 73 deletions

View File

@@ -60,7 +60,7 @@ const (
configVersion = 1
defaultTokenURL = "https://id.jottacloud.com/auth/realms/jottacloud/protocol/openid-connect/token"
defaultClientID = "jottacli"
defaultClientID = "jottacli" // Identified as "Jottacloud CLI" in "My logged in devices"
legacyTokenURL = "https://api.jottacloud.com/auth/v1/token"
legacyRegisterURL = "https://api.jottacloud.com/auth/v1/register"
@@ -69,7 +69,7 @@ const (
legacyConfigVersion = 0
)
func getWhitelabelServices() map[string]struct {
func getServices() map[string]struct {
name, domain, realm, clientID string
scopes []string
} {
@@ -80,15 +80,16 @@ func getWhitelabelServices() map[string]struct {
clientID string
scopes []string
}{
"jottacloud": {"Jottacloud", "id.jottacloud.com", "jottacloud", "desktop", []string{"openid", "jotta-default", "offline_access"}}, // Chose client id "desktop" here, will be identified as "Jottacloud for Desktop" in "My logged in devices", but could have used "jottacli" here as well.
"elkjop": {"Elkjøp Cloud (Norway)", "cloud.elkjop.no", "elkjop", "desktop", []string{"openid", "jotta-default", "offline_access"}},
"elgiganten_dk": {"Elgiganten Cloud (Denmark)", "cloud.elgiganten.dk", "elgiganten", "desktop", []string{"openid", "jotta-default", "offline_access"}},
"elgiganten_se": {"Elgiganten Cloud (Sweden)", "cloud.elgiganten.se", "elgiganten", "desktop", []string{"openid", "jotta-default", "offline_access"}},
"elko": {"ELKO Cloud (Iceland)", "cloud.elko.is", "elko", "desktop", []string{"openid", "jotta-default", "offline_access"}},
"gigantti": {"Gigantti Cloud (Finland)", "cloud.gigantti.fi", "gigantti", "desktop", []string{"openid", "jotta-default", "offline_access"}},
"telia_se": {"Telia Cloud (Sweden)", "cloud-auth.telia.se", "telia_se", "desktop", []string{"openid", "jotta-default", "offline_access"}},
"telia_no": {"Telia Sky (Norway)", "sky-auth.telia.no", "get", "desktop", []string{"openid", "jotta-default", "offline_access"}},
"tele2": {"Tele2 Cloud (Sweden)", "mittcloud-auth.tele2.se", "comhem", "desktop", []string{"openid", "jotta-default", "offline_access"}},
"onlime": {"Onlime (Denmark)", "cloud-auth.onlime.dk", "onlime_wl", "desktop", []string{"openid", "jotta-default", "offline_access"}},
"elkjop": {"Elkjøp Cloud (Norway)", "cloud.elkjop.no", "elkjop", "desktop", []string{"openid", "jotta-default", "offline_access"}},
"elgiganten_se": {"Elgiganten Cloud (Sweden)", "cloud.elgiganten.se", "elgiganten", "desktop", []string{"openid", "jotta-default", "offline_access"}},
"elgiganten_dk": {"Elgiganten Cloud (Denmark)", "cloud.elgiganten.dk", "elgiganten", "desktop", []string{"openid", "jotta-default", "offline_access"}},
"gigantti": {"Gigantti Cloud (Finland)", "cloud.gigantti.fi", "gigantti", "desktop", []string{"openid", "jotta-default", "offline_access"}},
"elko": {"ELKO Cloud (Iceland)", "cloud.elko.is", "elko", "desktop", []string{"openid", "jotta-default", "offline_access"}},
"letsgo": {"Let's Go Cloud (Germany)", "letsgo.jotta.cloud", "letsgo", "desktop-win", []string{"openid", "offline_access"}},
}
}
@@ -176,20 +177,32 @@ func Config(ctx context.Context, name string, m configmap.Mapper, conf fs.Config
}
return fs.ConfigChooseExclusiveFixed("auth_type_done", "config_type", `Type of authentication.`, []fs.OptionExample{{
Value: "standard",
Help: "Standard authentication.\nUse this if you're a normal Jottacloud user.",
Help: `Standard authentication.
This is primarily supported by the official service, but may also be supported
by some of the white-label services. It is designed for command-line
applications, and you will be asked to enter a single-use personal login token
which you must manually generate from the account security settings in the
web interface of your service.`,
}, {
Value: "whitelabel",
Help: "Whitelabel authentication.\nUse this if you are using the service offered by a third party such as Telia, Tele2, Onlime, Elkjøp, etc.",
Value: "traditional",
Help: `Traditional authentication.
This is supported by the official service and most of the white-label
services, you will be asked which service to connect to. You need to be on
a machine with an internet-connected web browser.`,
}, {
Value: "legacy",
Help: "Legacy authentication.\nThis is no longer supported by any known services and not recommended for normal users.",
Help: `Legacy authentication.
This is no longer supported by any known services and not recommended used.
You will be asked for your account's username and password.`,
}})
case "auth_type_done":
// Jump to next state according to config chosen
return fs.ConfigGoto(conf.Result)
case "standard": // configure a jottacloud backend using the modern JottaCli token based authentication
m.Set("configVersion", fmt.Sprint(configVersion))
return fs.ConfigInput("standard_token", "config_login_token", "Personal login token.\nGenerate here: https://www.jottacloud.com/web/secure")
return fs.ConfigInput("standard_token", "config_login_token", `Personal login token.
Generate it from the account security settings in the web interface of your
service, for the official service on https://www.jottacloud.com/web/secure.`)
case "standard_token":
loginToken := conf.Result
m.Set(configClientID, defaultClientID)
@@ -206,10 +219,10 @@ func Config(ctx context.Context, name string, m configmap.Mapper, conf fs.Config
return nil, fmt.Errorf("error while saving token: %w", err)
}
return fs.ConfigGoto("choose_device")
case "whitelabel":
whitelabels := getWhitelabelServices()
options := make([]fs.OptionExample, 0, len(whitelabels))
for key, val := range whitelabels {
case "traditional":
services := getServices()
options := make([]fs.OptionExample, 0, len(services))
for key, val := range services {
options = append(options, fs.OptionExample{
Value: key,
Help: val.name,
@@ -218,17 +231,17 @@ func Config(ctx context.Context, name string, m configmap.Mapper, conf fs.Config
sort.Slice(options, func(i, j int) bool {
return options[i].Help < options[j].Help
})
return fs.ConfigChooseExclusiveFixed("whitelabel_type", "config_whitelabel",
return fs.ConfigChooseExclusiveFixed("traditional_type", "config_traditional",
"White-label service. This decides the domain name to connect to and\nthe authentication configuration to use.",
options)
case "whitelabel_type":
whitelabel, ok := getWhitelabelServices()[conf.Result]
case "traditional_type":
service, ok := getServices()[conf.Result]
if !ok {
return nil, fmt.Errorf("unexpected whitelabel %q", conf.Result)
return nil, fmt.Errorf("unexpected service %q", conf.Result)
}
opts := rest.Opts{
Method: "GET",
RootURL: "https://" + whitelabel.domain + "/auth/realms/" + whitelabel.realm + "/.well-known/openid-configuration",
RootURL: "https://" + service.domain + "/auth/realms/" + service.realm + "/.well-known/openid-configuration",
}
var wellKnown api.WellKnown
srv := rest.NewClient(fshttp.NewClient(ctx))
@@ -237,14 +250,14 @@ func Config(ctx context.Context, name string, m configmap.Mapper, conf fs.Config
return nil, fmt.Errorf("failed to get authentication provider configuration: %w", err)
}
m.Set("configVersion", fmt.Sprint(configVersion))
m.Set(configClientID, whitelabel.clientID)
m.Set(configClientID, service.clientID)
m.Set(configTokenURL, wellKnown.TokenEndpoint)
return oauthutil.ConfigOut("choose_device", &oauthutil.Options{
OAuth2Config: &oauthutil.Config{
AuthURL: wellKnown.AuthorizationEndpoint,
TokenURL: wellKnown.TokenEndpoint,
ClientID: whitelabel.clientID,
Scopes: whitelabel.scopes,
ClientID: service.clientID,
Scopes: service.scopes,
RedirectURL: oauthutil.RedirectLocalhostURL,
},
})