diff --git a/controllers/auth.go b/controllers/auth.go
index 86e697cc..cff1cd4e 100644
--- a/controllers/auth.go
+++ b/controllers/auth.go
@@ -416,15 +416,8 @@ func (c *ApiController) Login() {
}
} else if provider.Category == "OAuth" {
// OAuth
-
- clientId := provider.ClientId
- clientSecret := provider.ClientSecret
- if provider.Type == "WeChat" && strings.Contains(c.Ctx.Request.UserAgent(), "MicroMessenger") {
- clientId = provider.ClientId2
- clientSecret = provider.ClientSecret2
- }
-
- idProvider := idp.GetIdProvider(provider.Type, provider.SubType, clientId, clientSecret, provider.AppId, authForm.RedirectUri, provider.Domain, provider.CustomAuthUrl, provider.CustomTokenUrl, provider.CustomUserInfoUrl)
+ idpInfo := object.FromProviderToIdpInfo(c.Ctx, provider)
+ idProvider := idp.GetIdProvider(idpInfo, authForm.RedirectUri)
if idProvider == nil {
c.ResponseError(fmt.Sprintf(c.T("storage:The provider type: %s is not supported"), provider.Type))
return
diff --git a/go.mod b/go.mod
index c1342ef6..93d7e295 100644
--- a/go.mod
+++ b/go.mod
@@ -39,6 +39,7 @@ require (
github.com/lib/pq v1.10.2
github.com/lor00x/goldap v0.0.0-20180618054307-a546dffdd1a3
github.com/markbates/goth v1.75.2
+ github.com/mitchellh/mapstructure v1.5.0
github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d // indirect
github.com/nyaruka/phonenumbers v1.1.5
github.com/pkoukk/tiktoken-go v0.1.1
diff --git a/idp/custom.go b/idp/custom.go
index 5447272b..8f99ccb0 100644
--- a/idp/custom.go
+++ b/idp/custom.go
@@ -20,32 +20,37 @@ import (
"fmt"
"io"
"net/http"
- _ "net/url"
- _ "time"
+ "github.com/casdoor/casdoor/util"
+ "github.com/mitchellh/mapstructure"
"golang.org/x/oauth2"
)
type CustomIdProvider struct {
- Client *http.Client
- Config *oauth2.Config
- UserInfoUrl string
+ Client *http.Client
+ Config *oauth2.Config
+
+ UserInfoURL string
+ TokenURL string
+ AuthURL string
+ UserMapping map[string]string
+ Scopes []string
}
-func NewCustomIdProvider(clientId string, clientSecret string, redirectUrl string, authUrl string, tokenUrl string, userInfoUrl string) *CustomIdProvider {
+func NewCustomIdProvider(idpInfo *ProviderInfo, redirectUrl string) *CustomIdProvider {
idp := &CustomIdProvider{}
- idp.UserInfoUrl = userInfoUrl
- config := &oauth2.Config{
- ClientID: clientId,
- ClientSecret: clientSecret,
+ idp.Config = &oauth2.Config{
+ ClientID: idpInfo.ClientId,
+ ClientSecret: idpInfo.ClientSecret,
RedirectURL: redirectUrl,
Endpoint: oauth2.Endpoint{
- AuthURL: authUrl,
- TokenURL: tokenUrl,
+ AuthURL: idpInfo.AuthURL,
+ TokenURL: idpInfo.TokenURL,
},
}
- idp.Config = config
+ idp.UserInfoURL = idpInfo.UserInfoURL
+ idp.UserMapping = idpInfo.UserMapping
return idp
}
@@ -60,22 +65,20 @@ func (idp *CustomIdProvider) GetToken(code string) (*oauth2.Token, error) {
}
type CustomUserInfo struct {
- Id string `json:"sub"`
- Name string `json:"preferred_username,omitempty"`
- DisplayName string `json:"name"`
- Email string `json:"email"`
- AvatarUrl string `json:"picture"`
- Status string `json:"status"`
- Msg string `json:"msg"`
+ Id string `mapstructure:"id"`
+ Username string `mapstructure:"username"`
+ DisplayName string `mapstructure:"displayName"`
+ Email string `mapstructure:"email"`
+ AvatarUrl string `mapstructure:"avatarUrl"`
}
func (idp *CustomIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo, error) {
- ctUserinfo := &CustomUserInfo{}
accessToken := token.AccessToken
- request, err := http.NewRequest("GET", idp.UserInfoUrl, nil)
+ request, err := http.NewRequest("GET", idp.UserInfoURL, nil)
if err != nil {
return nil, err
}
+
// add accessToken to request header
request.Header.Add("Authorization", fmt.Sprintf("Bearer %s", accessToken))
resp, err := idp.Client.Do(request)
@@ -89,21 +92,40 @@ func (idp *CustomIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo, error)
return nil, err
}
- err = json.Unmarshal(data, ctUserinfo)
+ var dataMap map[string]interface{}
+ err = json.Unmarshal(data, &dataMap)
if err != nil {
return nil, err
}
- if ctUserinfo.Status != "" {
- return nil, fmt.Errorf("err: %s", ctUserinfo.Msg)
+ // map user info
+ for k, v := range idp.UserMapping {
+ _, ok := dataMap[v]
+ if !ok {
+ return nil, fmt.Errorf("cannot find %s in user from castom provider", v)
+ }
+ dataMap[k] = dataMap[v]
+ }
+
+ // try to parse id to string
+ id, err := util.ParseIdToString(dataMap["id"])
+ if err != nil {
+ return nil, err
+ }
+ dataMap["id"] = id
+
+ customUserinfo := &CustomUserInfo{}
+ err = mapstructure.Decode(dataMap, customUserinfo)
+ if err != nil {
+ return nil, err
}
userInfo := &UserInfo{
- Id: ctUserinfo.Id,
- Username: ctUserinfo.Name,
- DisplayName: ctUserinfo.DisplayName,
- Email: ctUserinfo.Email,
- AvatarUrl: ctUserinfo.AvatarUrl,
+ Id: customUserinfo.Id,
+ Username: customUserinfo.Username,
+ DisplayName: customUserinfo.DisplayName,
+ Email: customUserinfo.Email,
+ AvatarUrl: customUserinfo.AvatarUrl,
}
return userInfo, nil
}
diff --git a/idp/provider.go b/idp/provider.go
index e563f399..9a9dadd1 100644
--- a/idp/provider.go
+++ b/idp/provider.go
@@ -32,72 +32,89 @@ type UserInfo struct {
AvatarUrl string
}
+type ProviderInfo struct {
+ Type string
+ SubType string
+ ClientId string
+ ClientSecret string
+ AppId string
+ HostUrl string
+ RedirectUrl string
+
+ TokenURL string
+ AuthURL string
+ UserInfoURL string
+ UserMapping map[string]string
+}
+
type IdProvider interface {
SetHttpClient(client *http.Client)
GetToken(code string) (*oauth2.Token, error)
GetUserInfo(token *oauth2.Token) (*UserInfo, error)
}
-func GetIdProvider(typ string, subType string, clientId string, clientSecret string, appId string, redirectUrl string, hostUrl string, authUrl string, tokenUrl string, userInfoUrl string) IdProvider {
- if typ == "GitHub" {
- return NewGithubIdProvider(clientId, clientSecret, redirectUrl)
- } else if typ == "Google" {
- return NewGoogleIdProvider(clientId, clientSecret, redirectUrl)
- } else if typ == "QQ" {
- return NewQqIdProvider(clientId, clientSecret, redirectUrl)
- } else if typ == "WeChat" {
- return NewWeChatIdProvider(clientId, clientSecret, redirectUrl)
- } else if typ == "Facebook" {
- return NewFacebookIdProvider(clientId, clientSecret, redirectUrl)
- } else if typ == "DingTalk" {
- return NewDingTalkIdProvider(clientId, clientSecret, redirectUrl)
- } else if typ == "Weibo" {
- return NewWeiBoIdProvider(clientId, clientSecret, redirectUrl)
- } else if typ == "Gitee" {
- return NewGiteeIdProvider(clientId, clientSecret, redirectUrl)
- } else if typ == "LinkedIn" {
- return NewLinkedInIdProvider(clientId, clientSecret, redirectUrl)
- } else if typ == "WeCom" {
- if subType == "Internal" {
- return NewWeComInternalIdProvider(clientId, clientSecret, redirectUrl)
- } else if subType == "Third-party" {
- return NewWeComIdProvider(clientId, clientSecret, redirectUrl)
+func GetIdProvider(idpInfo *ProviderInfo, redirectUrl string) IdProvider {
+ switch idpInfo.Type {
+ case "GitHub":
+ return NewGithubIdProvider(idpInfo.ClientId, idpInfo.ClientSecret, redirectUrl)
+ case "Google":
+ return NewGoogleIdProvider(idpInfo.ClientId, idpInfo.ClientSecret, redirectUrl)
+ case "QQ":
+ return NewQqIdProvider(idpInfo.ClientId, idpInfo.ClientSecret, redirectUrl)
+ case "WeChat":
+ return NewWeChatIdProvider(idpInfo.ClientId, idpInfo.ClientSecret, redirectUrl)
+ case "Facebook":
+ return NewFacebookIdProvider(idpInfo.ClientId, idpInfo.ClientSecret, redirectUrl)
+ case "DingTalk":
+ return NewDingTalkIdProvider(idpInfo.ClientId, idpInfo.ClientSecret, redirectUrl)
+ case "Weibo":
+ return NewWeiBoIdProvider(idpInfo.ClientId, idpInfo.ClientSecret, redirectUrl)
+ case "Gitee":
+ return NewGiteeIdProvider(idpInfo.ClientId, idpInfo.ClientSecret, redirectUrl)
+ case "LinkedIn":
+ return NewLinkedInIdProvider(idpInfo.ClientId, idpInfo.ClientSecret, redirectUrl)
+ case "WeCom":
+ if idpInfo.SubType == "Internal" {
+ return NewWeComInternalIdProvider(idpInfo.ClientId, idpInfo.ClientSecret, redirectUrl)
+ } else if idpInfo.SubType == "Third-party" {
+ return NewWeComIdProvider(idpInfo.ClientId, idpInfo.ClientSecret, redirectUrl)
} else {
return nil
}
- } else if typ == "Lark" {
- return NewLarkIdProvider(clientId, clientSecret, redirectUrl)
- } else if typ == "GitLab" {
- return NewGitlabIdProvider(clientId, clientSecret, redirectUrl)
- } else if typ == "Adfs" {
- return NewAdfsIdProvider(clientId, clientSecret, redirectUrl, hostUrl)
- } else if typ == "Baidu" {
- return NewBaiduIdProvider(clientId, clientSecret, redirectUrl)
- } else if typ == "Alipay" {
- return NewAlipayIdProvider(clientId, clientSecret, redirectUrl)
- } else if typ == "Custom" {
- return NewCustomIdProvider(clientId, clientSecret, redirectUrl, authUrl, tokenUrl, userInfoUrl)
- } else if typ == "Infoflow" {
- if subType == "Internal" {
- return NewInfoflowInternalIdProvider(clientId, clientSecret, appId, redirectUrl)
- } else if subType == "Third-party" {
- return NewInfoflowIdProvider(clientId, clientSecret, appId, redirectUrl)
+ case "Lark":
+ return NewLarkIdProvider(idpInfo.ClientId, idpInfo.ClientSecret, redirectUrl)
+ case "GitLab":
+ return NewGitlabIdProvider(idpInfo.ClientId, idpInfo.ClientSecret, redirectUrl)
+ case "Adfs":
+ return NewAdfsIdProvider(idpInfo.ClientId, idpInfo.ClientSecret, redirectUrl, idpInfo.HostUrl)
+ case "Baidu":
+ return NewBaiduIdProvider(idpInfo.ClientId, idpInfo.ClientSecret, redirectUrl)
+ case "Alipay":
+ return NewAlipayIdProvider(idpInfo.ClientId, idpInfo.ClientSecret, redirectUrl)
+ case "Custom":
+ return NewCustomIdProvider(idpInfo, redirectUrl)
+ case "Infoflow":
+ if idpInfo.SubType == "Internal" {
+ return NewInfoflowInternalIdProvider(idpInfo.ClientId, idpInfo.ClientSecret, idpInfo.AppId, redirectUrl)
+ } else if idpInfo.SubType == "Third-party" {
+ return NewInfoflowIdProvider(idpInfo.ClientId, idpInfo.ClientSecret, idpInfo.AppId, redirectUrl)
} else {
return nil
}
- } else if typ == "Casdoor" {
- return NewCasdoorIdProvider(clientId, clientSecret, redirectUrl, hostUrl)
- } else if typ == "Okta" {
- return NewOktaIdProvider(clientId, clientSecret, redirectUrl, hostUrl)
- } else if typ == "Douyin" {
- return NewDouyinIdProvider(clientId, clientSecret, redirectUrl)
- } else if isGothSupport(typ) {
- return NewGothIdProvider(typ, clientId, clientSecret, redirectUrl, hostUrl)
- } else if typ == "Bilibili" {
- return NewBilibiliIdProvider(clientId, clientSecret, redirectUrl)
+ case "Casdoor":
+ return NewCasdoorIdProvider(idpInfo.ClientId, idpInfo.ClientSecret, redirectUrl, idpInfo.HostUrl)
+ case "Okta":
+ return NewOktaIdProvider(idpInfo.ClientId, idpInfo.ClientSecret, redirectUrl, idpInfo.HostUrl)
+ case "Douyin":
+ return NewDouyinIdProvider(idpInfo.ClientId, idpInfo.ClientSecret, redirectUrl)
+ case "Bilibili":
+ return NewBilibiliIdProvider(idpInfo.ClientId, idpInfo.ClientSecret, redirectUrl)
+ default:
+ if isGothSupport(idpInfo.Type) {
+ return NewGothIdProvider(idpInfo.Type, idpInfo.ClientId, idpInfo.ClientSecret, redirectUrl, idpInfo.HostUrl)
+ }
+ return nil
}
-
- return nil
}
var gothList = []string{
diff --git a/object/provider.go b/object/provider.go
index 20cbc3c1..616eab7a 100644
--- a/object/provider.go
+++ b/object/provider.go
@@ -16,8 +16,11 @@ package object
import (
"fmt"
+ "strings"
+ "github.com/beego/beego/context"
"github.com/casdoor/casdoor/i18n"
+ "github.com/casdoor/casdoor/idp"
"github.com/casdoor/casdoor/pp"
"github.com/casdoor/casdoor/util"
"github.com/xorm-io/core"
@@ -28,21 +31,22 @@ type Provider struct {
Name string `xorm:"varchar(100) notnull pk unique" json:"name"`
CreatedTime string `xorm:"varchar(100)" json:"createdTime"`
- DisplayName string `xorm:"varchar(100)" json:"displayName"`
- Category string `xorm:"varchar(100)" json:"category"`
- Type string `xorm:"varchar(100)" json:"type"`
- SubType string `xorm:"varchar(100)" json:"subType"`
- Method string `xorm:"varchar(100)" json:"method"`
- ClientId string `xorm:"varchar(100)" json:"clientId"`
- ClientSecret string `xorm:"varchar(2000)" json:"clientSecret"`
- ClientId2 string `xorm:"varchar(100)" json:"clientId2"`
- ClientSecret2 string `xorm:"varchar(100)" json:"clientSecret2"`
- Cert string `xorm:"varchar(100)" json:"cert"`
- CustomAuthUrl string `xorm:"varchar(200)" json:"customAuthUrl"`
- CustomScope string `xorm:"varchar(200)" json:"customScope"`
- CustomTokenUrl string `xorm:"varchar(200)" json:"customTokenUrl"`
- CustomUserInfoUrl string `xorm:"varchar(200)" json:"customUserInfoUrl"`
- CustomLogo string `xorm:"varchar(200)" json:"customLogo"`
+ DisplayName string `xorm:"varchar(100)" json:"displayName"`
+ Category string `xorm:"varchar(100)" json:"category"`
+ Type string `xorm:"varchar(100)" json:"type"`
+ SubType string `xorm:"varchar(100)" json:"subType"`
+ Method string `xorm:"varchar(100)" json:"method"`
+ ClientId string `xorm:"varchar(100)" json:"clientId"`
+ ClientSecret string `xorm:"varchar(2000)" json:"clientSecret"`
+ ClientId2 string `xorm:"varchar(100)" json:"clientId2"`
+ ClientSecret2 string `xorm:"varchar(100)" json:"clientSecret2"`
+ Cert string `xorm:"varchar(100)" json:"cert"`
+ CustomAuthUrl string `xorm:"varchar(200)" json:"customAuthUrl"`
+ CustomTokenUrl string `xorm:"varchar(200)" json:"customTokenUrl"`
+ CustomUserInfoUrl string `xorm:"varchar(200)" json:"customUserInfoUrl"`
+ CustomLogo string `xorm:"varchar(200)" json:"customLogo"`
+ Scopes string `xorm:"varchar(100)" json:"scopes"`
+ UserMapping map[string]string `xorm:"varchar(500)" json:"userMapping"`
Host string `xorm:"varchar(100)" json:"host"`
Port int `json:"port"`
@@ -365,3 +369,27 @@ func providerChangeTrigger(oldName string, newName string) error {
return session.Commit()
}
+
+func FromProviderToIdpInfo(ctx *context.Context, provider *Provider) *idp.ProviderInfo {
+ providerInfo := &idp.ProviderInfo{
+ Type: provider.Type,
+ SubType: provider.SubType,
+ ClientId: provider.ClientId,
+ ClientSecret: provider.ClientSecret,
+ AppId: provider.AppId,
+ HostUrl: provider.Host,
+ TokenURL: provider.CustomTokenUrl,
+ AuthURL: provider.CustomAuthUrl,
+ UserInfoURL: provider.CustomUserInfoUrl,
+ UserMapping: provider.UserMapping,
+ }
+
+ if provider.Type == "WeChat" {
+ if ctx != nil && strings.Contains(ctx.Request.UserAgent(), "MicroMessenger") {
+ providerInfo.ClientId = provider.ClientId2
+ providerInfo.ClientSecret = provider.ClientSecret2
+ }
+ }
+
+ return providerInfo
+}
diff --git a/swagger/swagger.json b/swagger/swagger.json
index e6a6b17e..d20ddb91 100644
--- a/swagger/swagger.json
+++ b/swagger/swagger.json
@@ -6126,7 +6126,7 @@
"customLogo": {
"type": "string"
},
- "customScope": {
+ "scopes": {
"type": "string"
},
"customTokenUrl": {
diff --git a/swagger/swagger.yml b/swagger/swagger.yml
index 78e4785e..31d9623a 100644
--- a/swagger/swagger.yml
+++ b/swagger/swagger.yml
@@ -4026,7 +4026,7 @@ definitions:
type: string
customLogo:
type: string
- customScope:
+ scopes:
type: string
customTokenUrl:
type: string
diff --git a/util/string.go b/util/string.go
index e78c777f..2df12e1f 100644
--- a/util/string.go
+++ b/util/string.go
@@ -289,3 +289,18 @@ func HasString(strs []string, str string) bool {
}
return false
}
+
+func ParseIdToString(input interface{}) (string, error) {
+ switch v := input.(type) {
+ case string:
+ return v, nil
+ case int:
+ return strconv.Itoa(v), nil
+ case int64:
+ return strconv.FormatInt(v, 10), nil
+ case float64:
+ return strconv.FormatFloat(v, 'f', -1, 64), nil
+ default:
+ return "", fmt.Errorf("unsupported id type: %T", input)
+ }
+}
diff --git a/util/string_test.go b/util/string_test.go
index 720dbba8..c3027e77 100644
--- a/util/string_test.go
+++ b/util/string_test.go
@@ -246,3 +246,23 @@ func TestSnakeString(t *testing.T) {
})
}
}
+
+func TestParseId(t *testing.T) {
+ scenarios := []struct {
+ description string
+ input interface{}
+ expected interface{}
+ }{
+ {"Should be return 123456", "123456", "123456"},
+ {"Should be return 123456", 123456, "123456"},
+ {"Should be return 123456", int64(123456), "123456"},
+ {"Should be return 123456", float64(123456), "123456"},
+ }
+ for _, scenery := range scenarios {
+ t.Run(scenery.description, func(t *testing.T) {
+ actual, err := ParseIdToString(scenery.input)
+ assert.Nil(t, err, "The returned value not is expected")
+ assert.Equal(t, scenery.expected, actual, "The returned value not is expected")
+ })
+ }
+}
diff --git a/web/src/ProviderEditPage.js b/web/src/ProviderEditPage.js
index 9bb3aae6..b3677951 100644
--- a/web/src/ProviderEditPage.js
+++ b/web/src/ProviderEditPage.js
@@ -56,8 +56,10 @@ class ProviderEditPage extends React.Component {
}
if (res.status === "ok") {
+ const provider = res.data;
+ provider.userMapping = provider.userMapping || {};
this.setState({
- provider: res.data,
+ provider: provider,
});
} else {
Setting.showMessage("error", res.msg);
@@ -93,6 +95,40 @@ class ProviderEditPage extends React.Component {
});
}
+ updateUserMappingField(key, value) {
+ const provider = this.state.provider;
+ provider.userMapping[key] = value;
+ this.setState({
+ provider: provider,
+ });
+ }
+
+ renderUserMappingInput() {
+ return (
+
+ {Setting.getLabel(i18next.t("general:ID"), i18next.t("general:ID - Tooltip"))} :
+ {
+ this.updateUserMappingField("id", e.target.value);
+ }} />
+ {Setting.getLabel(i18next.t("signup:Username"), i18next.t("signup:Username - Tooltip"))} :
+ {
+ this.updateUserMappingField("username", e.target.value);
+ }} />
+ {Setting.getLabel(i18next.t("general:Display name"), i18next.t("general:Display name - Tooltip"))} :
+ {
+ this.updateUserMappingField("displayName", e.target.value);
+ }} />
+ {Setting.getLabel(i18next.t("general:Email"), i18next.t("general:Email - Tooltip"))} :
+ {
+ this.updateUserMappingField("email", e.target.value);
+ }} />
+ {Setting.getLabel(i18next.t("general:Avatar"), i18next.t("general:Avatar - Tooltip"))} :
+ {
+ this.updateUserMappingField("avatarUrl", e.target.value);
+ }} />
+
+ );
+ }
getClientIdLabel(provider) {
switch (provider.category) {
case "Email":
@@ -350,7 +386,7 @@ class ProviderEditPage extends React.Component {
}
if (value === "Custom") {
this.updateProviderField("customAuthUrl", "https://door.casdoor.com/login/oauth/authorize");
- this.updateProviderField("customScope", "openid profile email");
+ this.updateProviderField("scopes", "openid profile email");
this.updateProviderField("customTokenUrl", "https://door.casdoor.com/api/login/oauth/access_token");
this.updateProviderField("customUserInfoUrl", "https://door.casdoor.com/api/userinfo");
}
@@ -416,16 +452,6 @@ class ProviderEditPage extends React.Component {
}} />
-
-
- {Setting.getLabel(i18next.t("provider:Scope"), i18next.t("provider:Scope - Tooltip"))}
-
-
- {
- this.updateProviderField("customScope", e.target.value);
- }} />
-
-
{Setting.getLabel(i18next.t("provider:Token URL"), i18next.t("provider:Token URL - Tooltip"))}
@@ -436,6 +462,16 @@ class ProviderEditPage extends React.Component {
}} />
+
+
+ {Setting.getLabel(i18next.t("provider:Scope"), i18next.t("provider:Scope - Tooltip"))}
+
+
+ {
+ this.updateProviderField("scopes", e.target.value);
+ }} />
+
+
{Setting.getLabel(i18next.t("provider:UserInfo URL"), i18next.t("provider:UserInfo URL - Tooltip"))}
@@ -446,6 +482,14 @@ class ProviderEditPage extends React.Component {
}} />
+
+
+ {Setting.getLabel(i18next.t("provider:User mapping"), i18next.t("provider:User mapping - Tooltip"))} :
+
+
+ {this.renderUserMappingInput()}
+
+
{Setting.getLabel(i18next.t("general:Favicon"), i18next.t("general:Favicon - Tooltip"))} :
diff --git a/web/src/auth/Provider.js b/web/src/auth/Provider.js
index b1d84ba2..64cd0b44 100644
--- a/web/src/auth/Provider.js
+++ b/web/src/auth/Provider.js
@@ -448,7 +448,7 @@ export function getAuthUrl(application, provider, method) {
} else if (provider.type === "Douyin" || provider.type === "TikTok") {
return `${endpoint}?client_key=${provider.clientId}&redirect_uri=${redirectUri}&state=${state}&response_type=code&scope=${scope}`;
} else if (provider.type === "Custom") {
- return `${provider.customAuthUrl}?client_id=${provider.clientId}&redirect_uri=${redirectUri}&scope=${provider.customScope}&response_type=code&state=${state}`;
+ return `${provider.customAuthUrl}?client_id=${provider.clientId}&redirect_uri=${redirectUri}&scope=${provider.scopes}&response_type=code&state=${state}`;
} else if (provider.type === "Bilibili") {
return `${endpoint}#/?client_id=${provider.clientId}&return_url=${redirectUri}&state=${state}&response_type=code`;
} else if (provider.type === "Deezer") {
diff --git a/web/src/locales/de/data.json b/web/src/locales/de/data.json
index c28b5d2c..2b4f5ab2 100644
--- a/web/src/locales/de/data.json
+++ b/web/src/locales/de/data.json
@@ -570,8 +570,8 @@
"pricing": {
"Copy pricing page URL": "Preisseite URL kopieren",
"Edit Pricing": "Edit Pricing",
- "Free": "Kostenlos",
"Failed to get plans": "Es konnten keine Pläne abgerufen werden",
+ "Free": "Kostenlos",
"Getting started": "Loslegen",
"New Pricing": "New Pricing",
"Trial duration": "Testphase Dauer",
@@ -739,6 +739,8 @@
"Token URL - Tooltip": "Token-URL",
"Type": "Typ",
"Type - Tooltip": "Wählen Sie einen Typ aus",
+ "User mapping": "User mapping",
+ "User mapping - Tooltip": "User mapping - Tooltip",
"UserInfo URL": "UserInfo-URL",
"UserInfo URL - Tooltip": "UserInfo-URL",
"admin (Shared)": "admin (Shared)"
diff --git a/web/src/locales/en/data.json b/web/src/locales/en/data.json
index 9614254f..8b116f5a 100644
--- a/web/src/locales/en/data.json
+++ b/web/src/locales/en/data.json
@@ -739,6 +739,8 @@
"Token URL - Tooltip": "Token URL",
"Type": "Type",
"Type - Tooltip": "Select a type",
+ "User mapping": "User mapping",
+ "User mapping - Tooltip": "User mapping - Tooltip",
"UserInfo URL": "UserInfo URL",
"UserInfo URL - Tooltip": "UserInfo URL",
"admin (Shared)": "admin (Shared)"
diff --git a/web/src/locales/es/data.json b/web/src/locales/es/data.json
index 9303daea..b469cf15 100644
--- a/web/src/locales/es/data.json
+++ b/web/src/locales/es/data.json
@@ -739,6 +739,8 @@
"Token URL - Tooltip": "URL de token",
"Type": "Tipo",
"Type - Tooltip": "Seleccionar un tipo",
+ "User mapping": "User mapping",
+ "User mapping - Tooltip": "User mapping - Tooltip",
"UserInfo URL": "URL de información del usuario",
"UserInfo URL - Tooltip": "URL de información de usuario",
"admin (Shared)": "administrador (compartido)"
diff --git a/web/src/locales/fr/data.json b/web/src/locales/fr/data.json
index 2f029445..dc2e05f4 100644
--- a/web/src/locales/fr/data.json
+++ b/web/src/locales/fr/data.json
@@ -739,6 +739,8 @@
"Token URL - Tooltip": "URL de jeton",
"Type": "Type",
"Type - Tooltip": "Sélectionnez un type",
+ "User mapping": "User mapping",
+ "User mapping - Tooltip": "User mapping - Tooltip",
"UserInfo URL": "URL d'informations utilisateur",
"UserInfo URL - Tooltip": "URL d'informations sur l'utilisateur",
"admin (Shared)": "admin (Partagé)"
diff --git a/web/src/locales/id/data.json b/web/src/locales/id/data.json
index a1aef057..d2d04fc8 100644
--- a/web/src/locales/id/data.json
+++ b/web/src/locales/id/data.json
@@ -739,6 +739,8 @@
"Token URL - Tooltip": "Token URL: URL Token",
"Type": "Jenis",
"Type - Tooltip": "Pilih tipe",
+ "User mapping": "User mapping",
+ "User mapping - Tooltip": "User mapping - Tooltip",
"UserInfo URL": "URL UserInfo",
"UserInfo URL - Tooltip": "URL Informasi Pengguna",
"admin (Shared)": "Admin (Berbagi)"
diff --git a/web/src/locales/ja/data.json b/web/src/locales/ja/data.json
index c531a142..4986f3eb 100644
--- a/web/src/locales/ja/data.json
+++ b/web/src/locales/ja/data.json
@@ -739,6 +739,8 @@
"Token URL - Tooltip": "トークンURL",
"Type": "タイプ",
"Type - Tooltip": "タイプを選択してください",
+ "User mapping": "User mapping",
+ "User mapping - Tooltip": "User mapping - Tooltip",
"UserInfo URL": "UserInfo URLを日本語に翻訳すると、「ユーザー情報のURL」となります",
"UserInfo URL - Tooltip": "ユーザー情報URL",
"admin (Shared)": "管理者(共有)"
diff --git a/web/src/locales/ko/data.json b/web/src/locales/ko/data.json
index 62d40868..6d1f54b8 100644
--- a/web/src/locales/ko/data.json
+++ b/web/src/locales/ko/data.json
@@ -739,6 +739,8 @@
"Token URL - Tooltip": "토큰 URL",
"Type": "타입",
"Type - Tooltip": "유형을 선택하세요",
+ "User mapping": "User mapping",
+ "User mapping - Tooltip": "User mapping - Tooltip",
"UserInfo URL": "사용자 정보 URL",
"UserInfo URL - Tooltip": "UserInfo URL: 사용자 정보 URL",
"admin (Shared)": "관리자 (공유)"
diff --git a/web/src/locales/pt/data.json b/web/src/locales/pt/data.json
index e6ea369d..b40cff9e 100644
--- a/web/src/locales/pt/data.json
+++ b/web/src/locales/pt/data.json
@@ -739,6 +739,8 @@
"Token URL - Tooltip": "URL do Token",
"Type": "Tipo",
"Type - Tooltip": "Selecione um tipo",
+ "User mapping": "User mapping",
+ "User mapping - Tooltip": "User mapping - Tooltip",
"UserInfo URL": "URL do UserInfo",
"UserInfo URL - Tooltip": "URL do UserInfo",
"admin (Shared)": "admin (Compartilhado)"
diff --git a/web/src/locales/ru/data.json b/web/src/locales/ru/data.json
index 482f393d..edbb8044 100644
--- a/web/src/locales/ru/data.json
+++ b/web/src/locales/ru/data.json
@@ -739,6 +739,8 @@
"Token URL - Tooltip": "Токен URL",
"Type": "Тип",
"Type - Tooltip": "Выберите тип",
+ "User mapping": "User mapping",
+ "User mapping - Tooltip": "User mapping - Tooltip",
"UserInfo URL": "URL информации о пользователе",
"UserInfo URL - Tooltip": "URL пользовательской информации (URL информации о пользователе)",
"admin (Shared)": "администратор (общий)"
diff --git a/web/src/locales/vi/data.json b/web/src/locales/vi/data.json
index 180255c0..e92699f0 100644
--- a/web/src/locales/vi/data.json
+++ b/web/src/locales/vi/data.json
@@ -739,6 +739,8 @@
"Token URL - Tooltip": "Địa chỉ URL của Token",
"Type": "Kiểu",
"Type - Tooltip": "Chọn loại",
+ "User mapping": "User mapping",
+ "User mapping - Tooltip": "User mapping - Tooltip",
"UserInfo URL": "Đường dẫn UserInfo",
"UserInfo URL - Tooltip": "Địa chỉ URL của Thông tin người dùng",
"admin (Shared)": "quản trị viên (Chung)"
diff --git a/web/src/locales/zh/data.json b/web/src/locales/zh/data.json
index cae0e6a5..5c57c95d 100644
--- a/web/src/locales/zh/data.json
+++ b/web/src/locales/zh/data.json
@@ -570,8 +570,8 @@
"pricing": {
"Copy pricing page URL": "复制定价页面链接",
"Edit Pricing": "编辑定价",
- "Free": "免费",
"Failed to get plans": "未能获取计划",
+ "Free": "免费",
"Getting started": "开始使用",
"New Pricing": "添加定价",
"Trial duration": "试用期时长",
diff --git a/web/src/pricing/PricingPage.js b/web/src/pricing/PricingPage.js
index 9299f4ab..49ee6337 100644
--- a/web/src/pricing/PricingPage.js
+++ b/web/src/pricing/PricingPage.js
@@ -66,7 +66,7 @@ class PricingPage extends React.Component {
.then(results => {
const hasError = results.some(result => result.status === "error");
if (hasError) {
- Setting.showMessage("error", `${i18next.t("Failed to get plans")}`);
+ Setting.showMessage("error", i18next.t("pricing:Failed to get plans"));
return;
}
this.setState({
@@ -75,7 +75,7 @@ class PricingPage extends React.Component {
});
})
.catch(error => {
- Setting.showMessage("error", `Failed to get plans: ${error}`);
+ Setting.showMessage("error", i18next.t("pricing:Failed to get plans") + `: ${error}`);
});
}
diff --git a/web/yarn.lock b/web/yarn.lock
index f198b70b..1e5aa7a8 100644
--- a/web/yarn.lock
+++ b/web/yarn.lock
@@ -173,7 +173,7 @@
lru-cache "^5.1.1"
semver "^6.3.0"
-"@babel/helper-create-class-features-plugin@^7.18.6", "@babel/helper-create-class-features-plugin@^7.22.5":
+"@babel/helper-create-class-features-plugin@^7.18.6", "@babel/helper-create-class-features-plugin@^7.21.0", "@babel/helper-create-class-features-plugin@^7.22.5":
version "7.22.5"
resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.22.5.tgz#2192a1970ece4685fbff85b48da2c32fcb130b7c"
integrity sha512-xkb58MyOYIslxu3gKmVXmjTtUPvBU4odYzbiIQbWwLKIHCsx6UGZGX6F1IznMFVnDdirseUZopzN+ZRt8Xb33Q==
@@ -433,6 +433,16 @@
resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz#7844f9289546efa9febac2de4cfe358a050bd703"
integrity sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==
+"@babel/plugin-proposal-private-property-in-object@^7.21.11":
+ version "7.21.11"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.11.tgz#69d597086b6760c4126525cfa154f34631ff272c"
+ integrity sha512-0QZ8qP/3RLDVBwBFoWAwCtgcDZJVwA5LUJRZU8x2YFfKNuFq161wK3cuGrALu5yiPu+vzwTAg/sMWVNeWeNyaw==
+ dependencies:
+ "@babel/helper-annotate-as-pure" "^7.18.6"
+ "@babel/helper-create-class-features-plugin" "^7.21.0"
+ "@babel/helper-plugin-utils" "^7.20.2"
+ "@babel/plugin-syntax-private-property-in-object" "^7.14.5"
+
"@babel/plugin-proposal-unicode-property-regex@^7.4.4":
version "7.18.6"
resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.18.6.tgz#af613d2cd5e643643b65cded64207b15c85cb78e"