mirror of
https://github.com/casdoor/casdoor.git
synced 2025-05-23 02:35:49 +08:00
feat: support ssh key/pem file in DB syncer (#2727)
* feat: support connect database with ssh tunnel in syncer * feat: improve i18n translate * feat: improve code format and i18n
This commit is contained in:
parent
3a9ffedce4
commit
23c2ba3a2b
@ -168,3 +168,20 @@ func (c *ApiController) RunSyncer() {
|
|||||||
|
|
||||||
c.ResponseOk()
|
c.ResponseOk()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *ApiController) TestSyncerDb() {
|
||||||
|
var syncer object.Syncer
|
||||||
|
err := json.Unmarshal(c.Ctx.Input.RequestBody, &syncer)
|
||||||
|
if err != nil {
|
||||||
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = object.TestSyncerDb(syncer)
|
||||||
|
if err != nil {
|
||||||
|
c.ResponseError(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.ResponseOk()
|
||||||
|
}
|
||||||
|
2
go.mod
2
go.mod
@ -59,7 +59,7 @@ require (
|
|||||||
github.com/xorm-io/core v0.7.4
|
github.com/xorm-io/core v0.7.4
|
||||||
github.com/xorm-io/xorm v1.1.6
|
github.com/xorm-io/xorm v1.1.6
|
||||||
github.com/yusufpapurcu/wmi v1.2.2 // indirect
|
github.com/yusufpapurcu/wmi v1.2.2 // indirect
|
||||||
golang.org/x/crypto v0.14.0
|
golang.org/x/crypto v0.19.0
|
||||||
golang.org/x/net v0.17.0
|
golang.org/x/net v0.17.0
|
||||||
golang.org/x/oauth2 v0.13.0
|
golang.org/x/oauth2 v0.13.0
|
||||||
google.golang.org/api v0.150.0
|
google.golang.org/api v0.150.0
|
||||||
|
12
go.sum
12
go.sum
@ -2117,8 +2117,9 @@ golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45
|
|||||||
golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio=
|
golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio=
|
||||||
golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw=
|
golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw=
|
||||||
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
|
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
|
||||||
golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc=
|
|
||||||
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
|
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
|
||||||
|
golang.org/x/crypto v0.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo=
|
||||||
|
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
|
||||||
golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
golang.org/x/exp v0.0.0-20181106170214-d68db9428509/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/exp v0.0.0-20181106170214-d68db9428509/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
@ -2447,8 +2448,9 @@ golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|||||||
golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
|
|
||||||
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y=
|
||||||
|
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
@ -2465,8 +2467,9 @@ golang.org/x/term v0.9.0/go.mod h1:M6DEAAIenWoTxdKrOltXcmDY3rSplQUkrvaDU5FcQyo=
|
|||||||
golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o=
|
golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o=
|
||||||
golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU=
|
golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU=
|
||||||
golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
|
golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
|
||||||
golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek=
|
|
||||||
golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U=
|
golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U=
|
||||||
|
golang.org/x/term v0.17.0 h1:mkTF7LCd6WGJNL3K1Ad7kwxNfYAW6a8a8QqtMblp/4U=
|
||||||
|
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
|
||||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
@ -2486,8 +2489,9 @@ golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
|||||||
golang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
golang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||||
golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||||
golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||||
golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
|
|
||||||
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||||
|
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
||||||
|
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
|
@ -32,8 +32,9 @@ import (
|
|||||||
_ "github.com/denisenkom/go-mssqldb" // db = mssql
|
_ "github.com/denisenkom/go-mssqldb" // db = mssql
|
||||||
_ "github.com/go-sql-driver/mysql" // db = mysql
|
_ "github.com/go-sql-driver/mysql" // db = mysql
|
||||||
_ "github.com/lib/pq" // db = postgres
|
_ "github.com/lib/pq" // db = postgres
|
||||||
"github.com/xorm-io/core"
|
|
||||||
"github.com/xorm-io/xorm"
|
"github.com/xorm-io/xorm"
|
||||||
|
"github.com/xorm-io/xorm/core"
|
||||||
|
"github.com/xorm-io/xorm/names"
|
||||||
_ "modernc.org/sqlite" // db = sqlite
|
_ "modernc.org/sqlite" // db = sqlite
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -98,7 +99,7 @@ func InitAdapter() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
tableNamePrefix := conf.GetConfigString("tableNamePrefix")
|
tableNamePrefix := conf.GetConfigString("tableNamePrefix")
|
||||||
tbMapper := core.NewPrefixMapper(core.SnakeMapper{}, tableNamePrefix)
|
tbMapper := names.NewPrefixMapper(names.SnakeMapper{}, tableNamePrefix)
|
||||||
ormer.Engine.SetTableMapper(tbMapper)
|
ormer.Engine.SetTableMapper(tbMapper)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -118,6 +119,7 @@ type Ormer struct {
|
|||||||
driverName string
|
driverName string
|
||||||
dataSourceName string
|
dataSourceName string
|
||||||
dbName string
|
dbName string
|
||||||
|
Db *sql.DB
|
||||||
Engine *xorm.Engine
|
Engine *xorm.Engine
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -127,6 +129,13 @@ func finalizer(a *Ormer) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if a.Db != nil {
|
||||||
|
err = a.Db.Close()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewAdapter is the constructor for Ormer.
|
// NewAdapter is the constructor for Ormer.
|
||||||
@ -148,6 +157,26 @@ func NewAdapter(driverName string, dataSourceName string, dbName string) (*Ormer
|
|||||||
return a, nil
|
return a, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewAdapterFromdb is the constructor for Ormer.
|
||||||
|
func NewAdapterFromDb(driverName string, dataSourceName string, dbName string, db *sql.DB) (*Ormer, error) {
|
||||||
|
a := &Ormer{}
|
||||||
|
a.driverName = driverName
|
||||||
|
a.dataSourceName = dataSourceName
|
||||||
|
a.dbName = dbName
|
||||||
|
a.Db = db
|
||||||
|
|
||||||
|
// Open the DB, create it if not existed.
|
||||||
|
err := a.openFromDb(a.Db)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Call the destructor when the object is released.
|
||||||
|
runtime.SetFinalizer(a, finalizer)
|
||||||
|
|
||||||
|
return a, nil
|
||||||
|
}
|
||||||
|
|
||||||
func refineDataSourceNameForPostgres(dataSourceName string) string {
|
func refineDataSourceNameForPostgres(dataSourceName string) string {
|
||||||
reg := regexp.MustCompile(`dbname=[^ ]+\s*`)
|
reg := regexp.MustCompile(`dbname=[^ ]+\s*`)
|
||||||
return reg.ReplaceAllString(dataSourceName, "")
|
return reg.ReplaceAllString(dataSourceName, "")
|
||||||
@ -226,6 +255,30 @@ func (a *Ormer) open() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *Ormer) openFromDb(db *sql.DB) error {
|
||||||
|
dataSourceName := a.dataSourceName + a.dbName
|
||||||
|
if a.driverName != "mysql" {
|
||||||
|
dataSourceName = a.dataSourceName
|
||||||
|
}
|
||||||
|
|
||||||
|
xormDb := core.FromDB(db)
|
||||||
|
|
||||||
|
engine, err := xorm.NewEngineWithDB(a.driverName, dataSourceName, xormDb)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if a.driverName == "postgres" {
|
||||||
|
schema := util.GetValueFromDataSourceName("search_path", dataSourceName)
|
||||||
|
if schema != "" {
|
||||||
|
engine.SetSchema(schema)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
a.Engine = engine
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (a *Ormer) close() {
|
func (a *Ormer) close() {
|
||||||
_ = a.Engine.Close()
|
_ = a.Engine.Close()
|
||||||
a.Engine = nil
|
a.Engine = nil
|
||||||
|
@ -39,11 +39,17 @@ type Syncer struct {
|
|||||||
Type string `xorm:"varchar(100)" json:"type"`
|
Type string `xorm:"varchar(100)" json:"type"`
|
||||||
DatabaseType string `xorm:"varchar(100)" json:"databaseType"`
|
DatabaseType string `xorm:"varchar(100)" json:"databaseType"`
|
||||||
SslMode string `xorm:"varchar(100)" json:"sslMode"`
|
SslMode string `xorm:"varchar(100)" json:"sslMode"`
|
||||||
|
SshType string `xorm:"varchar(100)" json:"sshType"`
|
||||||
|
|
||||||
Host string `xorm:"varchar(100)" json:"host"`
|
Host string `xorm:"varchar(100)" json:"host"`
|
||||||
Port int `json:"port"`
|
Port int `json:"port"`
|
||||||
User string `xorm:"varchar(100)" json:"user"`
|
User string `xorm:"varchar(100)" json:"user"`
|
||||||
Password string `xorm:"varchar(150)" json:"password"`
|
Password string `xorm:"varchar(150)" json:"password"`
|
||||||
|
SshHost string `xorm:"varchar(100)" json:"sshHost"`
|
||||||
|
SshPort int `json:"sshPort"`
|
||||||
|
SshUser string `xorm:"varchar(100)" json:"sshUser"`
|
||||||
|
SshPassword string `xorm:"varchar(150)" json:"sshPassword"`
|
||||||
|
Cert string `xorm:"varchar(100)" json:"cert"`
|
||||||
Database string `xorm:"varchar(100)" json:"database"`
|
Database string `xorm:"varchar(100)" json:"database"`
|
||||||
Table string `xorm:"varchar(100)" json:"table"`
|
Table string `xorm:"varchar(100)" json:"table"`
|
||||||
TableColumns []*TableColumn `xorm:"mediumtext" json:"tableColumns"`
|
TableColumns []*TableColumn `xorm:"mediumtext" json:"tableColumns"`
|
||||||
@ -279,3 +285,25 @@ func RunSyncer(syncer *Syncer) error {
|
|||||||
|
|
||||||
return syncer.syncUsers()
|
return syncer.syncUsers()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestSyncerDb(syncer Syncer) error {
|
||||||
|
oldSyncer, err := getSyncer(syncer.Owner, syncer.Name)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if syncer.Password == "***" {
|
||||||
|
syncer.Password = oldSyncer.Password
|
||||||
|
}
|
||||||
|
|
||||||
|
err = syncer.initAdapter()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = syncer.Ormer.Engine.Ping()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
@ -15,12 +15,17 @@
|
|||||||
package object
|
package object
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
|
"database/sql/driver"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"golang.org/x/crypto/ssh"
|
||||||
|
|
||||||
"github.com/casdoor/casdoor/util"
|
"github.com/casdoor/casdoor/util"
|
||||||
|
"github.com/go-sql-driver/mysql"
|
||||||
)
|
)
|
||||||
|
|
||||||
type OriginalUser = User
|
type OriginalUser = User
|
||||||
@ -124,6 +129,19 @@ func (syncer *Syncer) calculateHash(user *OriginalUser) string {
|
|||||||
return util.GetMd5Hash(s)
|
return util.GetMd5Hash(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type dsnConnector struct {
|
||||||
|
dsn string
|
||||||
|
driver driver.Driver
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t dsnConnector) Connect(ctx context.Context) (driver.Conn, error) {
|
||||||
|
return t.driver.Open(t.dsn)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t dsnConnector) Driver() driver.Driver {
|
||||||
|
return t.driver
|
||||||
|
}
|
||||||
|
|
||||||
func (syncer *Syncer) initAdapter() error {
|
func (syncer *Syncer) initAdapter() error {
|
||||||
if syncer.Ormer != nil {
|
if syncer.Ormer != nil {
|
||||||
return nil
|
return nil
|
||||||
@ -142,12 +160,38 @@ func (syncer *Syncer) initAdapter() error {
|
|||||||
dataSourceName = fmt.Sprintf("%s:%s@tcp(%s:%d)/", syncer.User, syncer.Password, syncer.Host, syncer.Port)
|
dataSourceName = fmt.Sprintf("%s:%s@tcp(%s:%d)/", syncer.User, syncer.Password, syncer.Host, syncer.Port)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var db *sql.DB
|
||||||
|
var err error
|
||||||
|
|
||||||
|
if syncer.SshType != "" && (syncer.DatabaseType == "mysql" || syncer.DatabaseType == "postgres" || syncer.DatabaseType == "mssql") {
|
||||||
|
var dial *ssh.Client
|
||||||
|
if syncer.SshType == "password" {
|
||||||
|
dial, err = DialWithPassword(syncer.SshUser, syncer.SshPassword, syncer.SshHost, syncer.SshPort)
|
||||||
|
} else {
|
||||||
|
dial, err = DialWithCert(syncer.SshUser, syncer.Owner+"/"+syncer.Cert, syncer.SshHost, syncer.SshPort)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if syncer.DatabaseType == "mysql" {
|
||||||
|
dataSourceName = fmt.Sprintf("%s:%s@%s(%s:%d)/", syncer.User, syncer.Password, syncer.Owner+syncer.Name, syncer.Host, syncer.Port)
|
||||||
|
mysql.RegisterDialContext(syncer.Owner+syncer.Name, (&ViaSSHDialer{Client: dial, Context: nil}).MysqlDial)
|
||||||
|
} else if syncer.DatabaseType == "postgres" || syncer.DatabaseType == "mssql" {
|
||||||
|
db = sql.OpenDB(dsnConnector{dsn: dataSourceName, driver: &ViaSSHDialer{Client: dial, Context: nil, DatabaseType: syncer.DatabaseType}})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if !isCloudIntranet {
|
if !isCloudIntranet {
|
||||||
dataSourceName = strings.ReplaceAll(dataSourceName, "dbi.", "db.")
|
dataSourceName = strings.ReplaceAll(dataSourceName, "dbi.", "db.")
|
||||||
}
|
}
|
||||||
|
|
||||||
var err error
|
if db != nil {
|
||||||
syncer.Ormer, err = NewAdapter(syncer.DatabaseType, dataSourceName, syncer.Database)
|
syncer.Ormer, err = NewAdapterFromDb(syncer.DatabaseType, dataSourceName, syncer.Database, db)
|
||||||
|
} else {
|
||||||
|
syncer.Ormer, err = NewAdapter(syncer.DatabaseType, dataSourceName, syncer.Database)
|
||||||
|
}
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
116
object/viaSSHDialer.go
Normal file
116
object/viaSSHDialer.go
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
// Copyright 2024 The Casdoor Authors. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package object
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"database/sql/driver"
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
mssql "github.com/denisenkom/go-mssqldb"
|
||||||
|
|
||||||
|
"github.com/lib/pq"
|
||||||
|
"golang.org/x/crypto/ssh"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ViaSSHDialer struct {
|
||||||
|
Client *ssh.Client
|
||||||
|
Context *context.Context
|
||||||
|
DatabaseType string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *ViaSSHDialer) MysqlDial(ctx context.Context, addr string) (net.Conn, error) {
|
||||||
|
return v.Client.Dial("tcp", addr)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *ViaSSHDialer) Open(s string) (_ driver.Conn, err error) {
|
||||||
|
if v.DatabaseType == "mssql" {
|
||||||
|
c, err := mssql.NewConnector(s)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
c.Dialer = v
|
||||||
|
return c.Connect(context.Background())
|
||||||
|
} else if v.DatabaseType == "postgres" {
|
||||||
|
return pq.DialOpen(v, s)
|
||||||
|
}
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *ViaSSHDialer) Dial(network, address string) (net.Conn, error) {
|
||||||
|
return v.Client.Dial(network, address)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *ViaSSHDialer) DialContext(ctx context.Context, network string, addr string) (net.Conn, error) {
|
||||||
|
return v.Client.DialContext(ctx, network, addr)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *ViaSSHDialer) DialTimeout(network, address string, timeout time.Duration) (net.Conn, error) {
|
||||||
|
return v.Client.Dial(network, address)
|
||||||
|
}
|
||||||
|
|
||||||
|
func DialWithPassword(SshUser string, SshPassword string, SshHost string, SshPort int) (*ssh.Client, error) {
|
||||||
|
address := fmt.Sprintf("%s:%d", SshHost, SshPort)
|
||||||
|
config := &ssh.ClientConfig{
|
||||||
|
User: SshUser,
|
||||||
|
Auth: []ssh.AuthMethod{
|
||||||
|
ssh.Password(SshPassword),
|
||||||
|
},
|
||||||
|
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
|
||||||
|
}
|
||||||
|
|
||||||
|
return ssh.Dial("tcp", address, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
func DialWithCert(SshUser string, CertId string, SshHost string, SshPort int) (*ssh.Client, error) {
|
||||||
|
address := fmt.Sprintf("%s:%d", SshHost, SshPort)
|
||||||
|
config := &ssh.ClientConfig{
|
||||||
|
User: SshUser,
|
||||||
|
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
|
||||||
|
}
|
||||||
|
|
||||||
|
cert, err := GetCert(CertId)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
signer, err := ssh.ParsePrivateKey([]byte(cert.PrivateKey))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
config.Auth = []ssh.AuthMethod{
|
||||||
|
ssh.PublicKeys(signer),
|
||||||
|
}
|
||||||
|
return ssh.Dial("tcp", address, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
func DialWithPrivateKey(SshUser string, PrivateKey []byte, SshHost string, SshPort int) (*ssh.Client, error) {
|
||||||
|
address := fmt.Sprintf("%s:%d", SshHost, SshPort)
|
||||||
|
config := &ssh.ClientConfig{
|
||||||
|
User: SshUser,
|
||||||
|
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
|
||||||
|
}
|
||||||
|
|
||||||
|
signer, err := ssh.ParsePrivateKey(PrivateKey)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
config.Auth = []ssh.AuthMethod{
|
||||||
|
ssh.PublicKeys(signer),
|
||||||
|
}
|
||||||
|
return ssh.Dial("tcp", address, config)
|
||||||
|
}
|
@ -233,6 +233,7 @@ func initAPI() {
|
|||||||
beego.Router("/api/add-syncer", &controllers.ApiController{}, "POST:AddSyncer")
|
beego.Router("/api/add-syncer", &controllers.ApiController{}, "POST:AddSyncer")
|
||||||
beego.Router("/api/delete-syncer", &controllers.ApiController{}, "POST:DeleteSyncer")
|
beego.Router("/api/delete-syncer", &controllers.ApiController{}, "POST:DeleteSyncer")
|
||||||
beego.Router("/api/run-syncer", &controllers.ApiController{}, "GET:RunSyncer")
|
beego.Router("/api/run-syncer", &controllers.ApiController{}, "GET:RunSyncer")
|
||||||
|
beego.Router("/api/test-syncer-db", &controllers.ApiController{}, "POST:TestSyncerDb")
|
||||||
|
|
||||||
beego.Router("/api/get-webhooks", &controllers.ApiController{}, "GET:GetWebhooks")
|
beego.Router("/api/get-webhooks", &controllers.ApiController{}, "GET:GetWebhooks")
|
||||||
beego.Router("/api/get-webhook", &controllers.ApiController{}, "GET:GetWebhook")
|
beego.Router("/api/get-webhook", &controllers.ApiController{}, "GET:GetWebhook")
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import {Button, Card, Col, Input, InputNumber, Row, Select, Switch} from "antd";
|
import {Button, Card, Col, Input, InputNumber, Radio, Row, Select, Switch} from "antd";
|
||||||
import {LinkOutlined} from "@ant-design/icons";
|
import {LinkOutlined} from "@ant-design/icons";
|
||||||
import * as SyncerBackend from "./backend/SyncerBackend";
|
import * as SyncerBackend from "./backend/SyncerBackend";
|
||||||
import * as OrganizationBackend from "./backend/OrganizationBackend";
|
import * as OrganizationBackend from "./backend/OrganizationBackend";
|
||||||
@ -23,6 +23,7 @@ import SyncerTableColumnTable from "./table/SyncerTableColumnTable";
|
|||||||
|
|
||||||
import {Controlled as CodeMirror} from "react-codemirror2";
|
import {Controlled as CodeMirror} from "react-codemirror2";
|
||||||
import "codemirror/lib/codemirror.css";
|
import "codemirror/lib/codemirror.css";
|
||||||
|
import * as CertBackend from "./backend/CertBackend";
|
||||||
require("codemirror/theme/material-darker.css");
|
require("codemirror/theme/material-darker.css");
|
||||||
require("codemirror/mode/javascript/javascript");
|
require("codemirror/mode/javascript/javascript");
|
||||||
|
|
||||||
@ -32,11 +33,13 @@ class SyncerEditPage extends React.Component {
|
|||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = {
|
this.state = {
|
||||||
|
certs: [],
|
||||||
classes: props,
|
classes: props,
|
||||||
syncerName: props.match.params.syncerName,
|
syncerName: props.match.params.syncerName,
|
||||||
syncer: null,
|
syncer: null,
|
||||||
organizations: [],
|
organizations: [],
|
||||||
mode: props.location.mode !== undefined ? props.location.mode : "edit",
|
mode: props.location.mode !== undefined ? props.location.mode : "edit",
|
||||||
|
testDbLoading: false,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -64,12 +67,24 @@ class SyncerEditPage extends React.Component {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getCerts(owner) {
|
||||||
|
CertBackend.getCerts(owner)
|
||||||
|
.then((res) => {
|
||||||
|
this.setState({
|
||||||
|
certs: res.data || [],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
getOrganizations() {
|
getOrganizations() {
|
||||||
OrganizationBackend.getOrganizations("admin")
|
OrganizationBackend.getOrganizations("admin")
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
this.setState({
|
this.setState({
|
||||||
organizations: res.data || [],
|
organizations: res.data || [],
|
||||||
});
|
});
|
||||||
|
if (res.data) {
|
||||||
|
this.getCerts(`${res.data.owner}/${res.data.name}`);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -228,7 +243,7 @@ class SyncerEditPage extends React.Component {
|
|||||||
});
|
});
|
||||||
})}>
|
})}>
|
||||||
{
|
{
|
||||||
["Database", "LDAP", "Keycloak"]
|
["Database", "Keycloak"]
|
||||||
.map((item, index) => <Option key={index} value={item}>{item}</Option>)
|
.map((item, index) => <Option key={index} value={item}>{item}</Option>)
|
||||||
}
|
}
|
||||||
</Select>
|
</Select>
|
||||||
@ -317,7 +332,7 @@ class SyncerEditPage extends React.Component {
|
|||||||
{Setting.getLabel(i18next.t("general:Password"), i18next.t("general:Password - Tooltip"))} :
|
{Setting.getLabel(i18next.t("general:Password"), i18next.t("general:Password - Tooltip"))} :
|
||||||
</Col>
|
</Col>
|
||||||
<Col span={22} >
|
<Col span={22} >
|
||||||
<Input value={this.state.syncer.password} onChange={e => {
|
<Input.Password value={this.state.syncer.password} onChange={e => {
|
||||||
this.updateSyncerField("password", e.target.value);
|
this.updateSyncerField("password", e.target.value);
|
||||||
}} />
|
}} />
|
||||||
</Col>
|
</Col>
|
||||||
@ -332,6 +347,88 @@ class SyncerEditPage extends React.Component {
|
|||||||
}} />
|
}} />
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
|
{
|
||||||
|
this.state.syncer.databaseType === "mysql" || this.state.syncer.databaseType === "mssql" || this.state.syncer.databaseType === "postgres" ? (
|
||||||
|
<Row style={{marginTop: "20px"}} >
|
||||||
|
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||||
|
{Setting.getLabel(i18next.t("general:SSH type"), i18next.t("general:SSH type - Tooltip"))} :
|
||||||
|
</Col>
|
||||||
|
<Col span={22} >
|
||||||
|
<Radio.Group value={this.state.syncer.sshType} buttonStyle="solid" onChange={e => {
|
||||||
|
this.updateSyncerField("sshType", e.target.value);
|
||||||
|
}}>
|
||||||
|
<Radio.Button value="">{i18next.t("general:None")}</Radio.Button>
|
||||||
|
<Radio.Button value="password">{i18next.t("general:Password")}</Radio.Button>
|
||||||
|
<Radio.Button value="cert">{i18next.t("general:Cert")}</Radio.Button>
|
||||||
|
</Radio.Group>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
) : null
|
||||||
|
}
|
||||||
|
{
|
||||||
|
this.state.syncer.sshType && this.state.syncer.databaseType === "mysql" || this.state.syncer.databaseType === "mssql" || this.state.syncer.databaseType === "postgres" ? (
|
||||||
|
<React.Fragment>
|
||||||
|
<Row style={{marginTop: "20px"}} >
|
||||||
|
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||||
|
{Setting.getLabel(i18next.t("syncer:SSH host"), i18next.t("provider:Host - Tooltip"))} :
|
||||||
|
</Col>
|
||||||
|
<Col span={22} >
|
||||||
|
<Input prefix={<LinkOutlined />} value={this.state.syncer.sshHost} onChange={e => {
|
||||||
|
this.updateSyncerField("sshHost", e.target.value);
|
||||||
|
}} />
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
<Row style={{marginTop: "20px"}} >
|
||||||
|
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||||
|
{Setting.getLabel(i18next.t("syncer:SSH port"), i18next.t("provider:Port - Tooltip"))} :
|
||||||
|
</Col>
|
||||||
|
<Col span={22} >
|
||||||
|
<InputNumber value={this.state.syncer.sshPort} onChange={value => {
|
||||||
|
this.updateSyncerField("sshPort", value);
|
||||||
|
}} />
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
<Row style={{marginTop: "20px"}} >
|
||||||
|
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||||
|
{Setting.getLabel(i18next.t("syncer:SSH user"), i18next.t("general:User - Tooltip"))} :
|
||||||
|
</Col>
|
||||||
|
<Col span={22} >
|
||||||
|
<Input value={this.state.syncer.sshUser} onChange={e => {
|
||||||
|
this.updateSyncerField("sshUser", e.target.value);
|
||||||
|
}} />
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
{
|
||||||
|
this.state.syncer.sshType === "password" && (this.state.syncer.databaseType === "mysql" || this.state.syncer.databaseType === "mssql" || this.state.syncer.databaseType === "postgres") ?
|
||||||
|
(
|
||||||
|
<Row style={{marginTop: "20px"}} >
|
||||||
|
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||||
|
{Setting.getLabel(i18next.t("syncer:SSH password"), i18next.t("general:Password - Tooltip"))} :
|
||||||
|
</Col>
|
||||||
|
<Col span={22} >
|
||||||
|
<Input.Password value={this.state.syncer.sshPassword} onChange={e => {
|
||||||
|
this.updateSyncerField("ssh " + "sshPassword", e.target.value);
|
||||||
|
}} />
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
) : (
|
||||||
|
<Row style={{marginTop: "20px"}} >
|
||||||
|
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||||
|
{Setting.getLabel(i18next.t("general:SSH cert"), i18next.t("general:Cert - Tooltip"))} :
|
||||||
|
</Col>
|
||||||
|
<Col span={22} >
|
||||||
|
<Select virtual={false} style={{width: "100%"}} value={this.state.syncer.cert} onChange={(value => {this.updateSyncerField("cert", value);})}>
|
||||||
|
{
|
||||||
|
this.state?.certs.map((cert, index) => <Option key={index} value={cert.name}>{cert.name}</Option>)
|
||||||
|
}
|
||||||
|
</Select>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
</React.Fragment>
|
||||||
|
) : null
|
||||||
|
}
|
||||||
<Row style={{marginTop: "20px"}} >
|
<Row style={{marginTop: "20px"}} >
|
||||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||||
{Setting.getLabel(i18next.t("syncer:Table"), i18next.t("syncer:Table - Tooltip"))} :
|
{Setting.getLabel(i18next.t("syncer:Table"), i18next.t("syncer:Table - Tooltip"))} :
|
||||||
@ -343,6 +440,31 @@ class SyncerEditPage extends React.Component {
|
|||||||
}} />
|
}} />
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
|
<Row style={{marginTop: "20px"}} >
|
||||||
|
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||||
|
{Setting.getLabel(i18next.t("provider:DB test"), i18next.t("provider:DB test - Tooltip"))} :
|
||||||
|
</Col>
|
||||||
|
<Col span={2} >
|
||||||
|
<Button type={"primary"} loading={this.state.testDbLoading} onClick={() => {
|
||||||
|
this.setState({testDbLoading: true});
|
||||||
|
SyncerBackend.testSyncerDb(this.state.syncer)
|
||||||
|
.then((res) => {
|
||||||
|
if (res.status === "ok") {
|
||||||
|
this.setState({testDbLoading: false});
|
||||||
|
Setting.showMessage("success", i18next.t("syncer:Connect successfully"));
|
||||||
|
} else {
|
||||||
|
this.setState({testDbLoading: false});
|
||||||
|
Setting.showMessage("error", i18next.t("syncer:Failed to connect") + ": " + res.msg);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
this.setState({testDbLoading: false});
|
||||||
|
Setting.showMessage("error", `${i18next.t("general:Failed to connect to server")}: ${error}`);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}>{i18next.t("syncer:Test DB Connection")}</Button>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
<Row style={{marginTop: "20px"}} >
|
<Row style={{marginTop: "20px"}} >
|
||||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||||
{Setting.getLabel(i18next.t("syncer:Table columns"), i18next.t("syncer:Table columns - Tooltip"))} :
|
{Setting.getLabel(i18next.t("syncer:Table columns"), i18next.t("syncer:Table columns - Tooltip"))} :
|
||||||
|
@ -58,6 +58,18 @@ export function addSyncer(syncer) {
|
|||||||
}).then(res => res.json());
|
}).then(res => res.json());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function testSyncerDb(syncer) {
|
||||||
|
const newSyncer = Setting.deepCopy(syncer);
|
||||||
|
return fetch(`${Setting.ServerUrl}/api/test-syncer-db`, {
|
||||||
|
method: "POST",
|
||||||
|
credentials: "include",
|
||||||
|
body: JSON.stringify(newSyncer),
|
||||||
|
headers: {
|
||||||
|
"Accept-Language": Setting.getAcceptLanguage(),
|
||||||
|
},
|
||||||
|
}).then(res => res.json());
|
||||||
|
}
|
||||||
|
|
||||||
export function deleteSyncer(syncer) {
|
export function deleteSyncer(syncer) {
|
||||||
const newSyncer = Setting.deepCopy(syncer);
|
const newSyncer = Setting.deepCopy(syncer);
|
||||||
return fetch(`${Setting.ServerUrl}/api/delete-syncer`, {
|
return fetch(`${Setting.ServerUrl}/api/delete-syncer`, {
|
||||||
|
@ -324,6 +324,9 @@
|
|||||||
"Root cert - Tooltip": "Root cert - Tooltip",
|
"Root cert - Tooltip": "Root cert - Tooltip",
|
||||||
"SAML attributes": "SAML attributes",
|
"SAML attributes": "SAML attributes",
|
||||||
"SAML attributes - Tooltip": "SAML attributes - Tooltip",
|
"SAML attributes - Tooltip": "SAML attributes - Tooltip",
|
||||||
|
"SSH cert": "SSH cert",
|
||||||
|
"SSH type": "SSH type",
|
||||||
|
"SSH type - Tooltip": "The auth type of SSH connection",
|
||||||
"Save": "Save",
|
"Save": "Save",
|
||||||
"Save & Exit": "Save & Exit",
|
"Save & Exit": "Save & Exit",
|
||||||
"Session ID": "Session ID",
|
"Session ID": "Session ID",
|
||||||
@ -964,6 +967,10 @@
|
|||||||
"Is read-only": "Is read-only",
|
"Is read-only": "Is read-only",
|
||||||
"Is read-only - Tooltip": "Is read-only - Tooltip",
|
"Is read-only - Tooltip": "Is read-only - Tooltip",
|
||||||
"New Syncer": "New Syncer",
|
"New Syncer": "New Syncer",
|
||||||
|
"SSH host": "SSH host",
|
||||||
|
"SSH password": "SSH password",
|
||||||
|
"SSH port": "SSH port",
|
||||||
|
"SSH user": "SSH user",
|
||||||
"SSL mode": "SSL mode",
|
"SSL mode": "SSL mode",
|
||||||
"SSL mode - Tooltip": "SSL mode - Tooltip",
|
"SSL mode - Tooltip": "SSL mode - Tooltip",
|
||||||
"Sync interval": "Sync interval",
|
"Sync interval": "Sync interval",
|
||||||
|
@ -324,6 +324,9 @@
|
|||||||
"Root cert - Tooltip": "Root cert - Tooltip",
|
"Root cert - Tooltip": "Root cert - Tooltip",
|
||||||
"SAML attributes": "SAML attributes",
|
"SAML attributes": "SAML attributes",
|
||||||
"SAML attributes - Tooltip": "SAML attributes - Tooltip",
|
"SAML attributes - Tooltip": "SAML attributes - Tooltip",
|
||||||
|
"SSH cert": "SSH cert",
|
||||||
|
"SSH type": "SSH type",
|
||||||
|
"SSH type - Tooltip": "The auth type of SSH connection",
|
||||||
"Save": "Speichern",
|
"Save": "Speichern",
|
||||||
"Save & Exit": "Speichern und verlassen",
|
"Save & Exit": "Speichern und verlassen",
|
||||||
"Session ID": "Session-ID",
|
"Session ID": "Session-ID",
|
||||||
@ -964,6 +967,10 @@
|
|||||||
"Is read-only": "Is read-only",
|
"Is read-only": "Is read-only",
|
||||||
"Is read-only - Tooltip": "Is read-only - Tooltip",
|
"Is read-only - Tooltip": "Is read-only - Tooltip",
|
||||||
"New Syncer": "Neuer Syncer",
|
"New Syncer": "Neuer Syncer",
|
||||||
|
"SSH host": "SSH host",
|
||||||
|
"SSH password": "SSH password",
|
||||||
|
"SSH port": "SSH port",
|
||||||
|
"SSH user": "SSH user",
|
||||||
"SSL mode": "SSL mode",
|
"SSL mode": "SSL mode",
|
||||||
"SSL mode - Tooltip": "SSL mode - Tooltip",
|
"SSL mode - Tooltip": "SSL mode - Tooltip",
|
||||||
"Sync interval": "Synchronisierungsintervall",
|
"Sync interval": "Synchronisierungsintervall",
|
||||||
|
@ -324,6 +324,9 @@
|
|||||||
"Root cert - Tooltip": "Root cert - Tooltip",
|
"Root cert - Tooltip": "Root cert - Tooltip",
|
||||||
"SAML attributes": "SAML attributes",
|
"SAML attributes": "SAML attributes",
|
||||||
"SAML attributes - Tooltip": "SAML attributes - Tooltip",
|
"SAML attributes - Tooltip": "SAML attributes - Tooltip",
|
||||||
|
"SSH cert": "SSH cert",
|
||||||
|
"SSH type": "SSH type",
|
||||||
|
"SSH type - Tooltip": "The auth type of SSH connection",
|
||||||
"Save": "Save",
|
"Save": "Save",
|
||||||
"Save & Exit": "Save & Exit",
|
"Save & Exit": "Save & Exit",
|
||||||
"Session ID": "Session ID",
|
"Session ID": "Session ID",
|
||||||
@ -964,6 +967,10 @@
|
|||||||
"Is read-only": "Is read-only",
|
"Is read-only": "Is read-only",
|
||||||
"Is read-only - Tooltip": "Is read-only - Tooltip",
|
"Is read-only - Tooltip": "Is read-only - Tooltip",
|
||||||
"New Syncer": "New Syncer",
|
"New Syncer": "New Syncer",
|
||||||
|
"SSH host": "SSH host",
|
||||||
|
"SSH password": "SSH password",
|
||||||
|
"SSH port": "SSH port",
|
||||||
|
"SSH user": "SSH user",
|
||||||
"SSL mode": "SSL mode",
|
"SSL mode": "SSL mode",
|
||||||
"SSL mode - Tooltip": "The SSL mode used when connecting to the database",
|
"SSL mode - Tooltip": "The SSL mode used when connecting to the database",
|
||||||
"Sync interval": "Sync interval",
|
"Sync interval": "Sync interval",
|
||||||
|
@ -324,6 +324,9 @@
|
|||||||
"Root cert - Tooltip": "Root cert - Tooltip",
|
"Root cert - Tooltip": "Root cert - Tooltip",
|
||||||
"SAML attributes": "SAML attributes",
|
"SAML attributes": "SAML attributes",
|
||||||
"SAML attributes - Tooltip": "SAML attributes - Tooltip",
|
"SAML attributes - Tooltip": "SAML attributes - Tooltip",
|
||||||
|
"SSH cert": "SSH cert",
|
||||||
|
"SSH type": "SSH type",
|
||||||
|
"SSH type - Tooltip": "The auth type of SSH connection",
|
||||||
"Save": "Guardar",
|
"Save": "Guardar",
|
||||||
"Save & Exit": "Guardar y salir",
|
"Save & Exit": "Guardar y salir",
|
||||||
"Session ID": "ID de sesión",
|
"Session ID": "ID de sesión",
|
||||||
@ -964,6 +967,10 @@
|
|||||||
"Is read-only": "Is read-only",
|
"Is read-only": "Is read-only",
|
||||||
"Is read-only - Tooltip": "Is read-only - Tooltip",
|
"Is read-only - Tooltip": "Is read-only - Tooltip",
|
||||||
"New Syncer": "Nuevo Syncer",
|
"New Syncer": "Nuevo Syncer",
|
||||||
|
"SSH host": "SSH host",
|
||||||
|
"SSH password": "SSH password",
|
||||||
|
"SSH port": "SSH port",
|
||||||
|
"SSH user": "SSH user",
|
||||||
"SSL mode": "SSL mode",
|
"SSL mode": "SSL mode",
|
||||||
"SSL mode - Tooltip": "SSL mode - Tooltip",
|
"SSL mode - Tooltip": "SSL mode - Tooltip",
|
||||||
"Sync interval": "Intervalo de sincronización",
|
"Sync interval": "Intervalo de sincronización",
|
||||||
|
@ -324,6 +324,9 @@
|
|||||||
"Root cert - Tooltip": "Root cert - Tooltip",
|
"Root cert - Tooltip": "Root cert - Tooltip",
|
||||||
"SAML attributes": "SAML attributes",
|
"SAML attributes": "SAML attributes",
|
||||||
"SAML attributes - Tooltip": "SAML attributes - Tooltip",
|
"SAML attributes - Tooltip": "SAML attributes - Tooltip",
|
||||||
|
"SSH cert": "SSH cert",
|
||||||
|
"SSH type": "SSH type",
|
||||||
|
"SSH type - Tooltip": "The auth type of SSH connection",
|
||||||
"Save": "Save",
|
"Save": "Save",
|
||||||
"Save & Exit": "Save & Exit",
|
"Save & Exit": "Save & Exit",
|
||||||
"Session ID": "Session ID",
|
"Session ID": "Session ID",
|
||||||
@ -964,6 +967,10 @@
|
|||||||
"Is read-only": "Is read-only",
|
"Is read-only": "Is read-only",
|
||||||
"Is read-only - Tooltip": "Is read-only - Tooltip",
|
"Is read-only - Tooltip": "Is read-only - Tooltip",
|
||||||
"New Syncer": "New Syncer",
|
"New Syncer": "New Syncer",
|
||||||
|
"SSH host": "SSH host",
|
||||||
|
"SSH password": "SSH password",
|
||||||
|
"SSH port": "SSH port",
|
||||||
|
"SSH user": "SSH user",
|
||||||
"SSL mode": "SSL mode",
|
"SSL mode": "SSL mode",
|
||||||
"SSL mode - Tooltip": "SSL mode - Tooltip",
|
"SSL mode - Tooltip": "SSL mode - Tooltip",
|
||||||
"Sync interval": "Sync interval",
|
"Sync interval": "Sync interval",
|
||||||
|
@ -324,6 +324,9 @@
|
|||||||
"Root cert - Tooltip": "Root cert - Tooltip",
|
"Root cert - Tooltip": "Root cert - Tooltip",
|
||||||
"SAML attributes": "SAML attributes",
|
"SAML attributes": "SAML attributes",
|
||||||
"SAML attributes - Tooltip": "SAML attributes - Tooltip",
|
"SAML attributes - Tooltip": "SAML attributes - Tooltip",
|
||||||
|
"SSH cert": "SSH cert",
|
||||||
|
"SSH type": "SSH type",
|
||||||
|
"SSH type - Tooltip": "The auth type of SSH connection",
|
||||||
"Save": "Save",
|
"Save": "Save",
|
||||||
"Save & Exit": "Save & Exit",
|
"Save & Exit": "Save & Exit",
|
||||||
"Session ID": "Session ID",
|
"Session ID": "Session ID",
|
||||||
@ -964,6 +967,10 @@
|
|||||||
"Is read-only": "Is read-only",
|
"Is read-only": "Is read-only",
|
||||||
"Is read-only - Tooltip": "Is read-only - Tooltip",
|
"Is read-only - Tooltip": "Is read-only - Tooltip",
|
||||||
"New Syncer": "New Syncer",
|
"New Syncer": "New Syncer",
|
||||||
|
"SSH host": "SSH host",
|
||||||
|
"SSH password": "SSH password",
|
||||||
|
"SSH port": "SSH port",
|
||||||
|
"SSH user": "SSH user",
|
||||||
"SSL mode": "SSL mode",
|
"SSL mode": "SSL mode",
|
||||||
"SSL mode - Tooltip": "SSL mode - Tooltip",
|
"SSL mode - Tooltip": "SSL mode - Tooltip",
|
||||||
"Sync interval": "Sync interval",
|
"Sync interval": "Sync interval",
|
||||||
|
@ -324,6 +324,9 @@
|
|||||||
"Root cert - Tooltip": "Root cert - Tooltip",
|
"Root cert - Tooltip": "Root cert - Tooltip",
|
||||||
"SAML attributes": "SAML attributes",
|
"SAML attributes": "SAML attributes",
|
||||||
"SAML attributes - Tooltip": "SAML attributes - Tooltip",
|
"SAML attributes - Tooltip": "SAML attributes - Tooltip",
|
||||||
|
"SSH cert": "SSH cert",
|
||||||
|
"SSH type": "SSH type",
|
||||||
|
"SSH type - Tooltip": "The auth type of SSH connection",
|
||||||
"Save": "Enregistrer",
|
"Save": "Enregistrer",
|
||||||
"Save & Exit": "Enregistrer et quitter",
|
"Save & Exit": "Enregistrer et quitter",
|
||||||
"Session ID": "Identifiant de session",
|
"Session ID": "Identifiant de session",
|
||||||
@ -964,6 +967,10 @@
|
|||||||
"Is read-only": "Est en lecture seule",
|
"Is read-only": "Est en lecture seule",
|
||||||
"Is read-only - Tooltip": "En lecture seule - Infobulle",
|
"Is read-only - Tooltip": "En lecture seule - Infobulle",
|
||||||
"New Syncer": "Nouveau synchroniseur",
|
"New Syncer": "Nouveau synchroniseur",
|
||||||
|
"SSH host": "SSH host",
|
||||||
|
"SSH password": "SSH password",
|
||||||
|
"SSH port": "SSH port",
|
||||||
|
"SSH user": "SSH user",
|
||||||
"SSL mode": "SSL mode",
|
"SSL mode": "SSL mode",
|
||||||
"SSL mode - Tooltip": "SSL mode - Tooltip",
|
"SSL mode - Tooltip": "SSL mode - Tooltip",
|
||||||
"Sync interval": "Intervalle de synchronisation",
|
"Sync interval": "Intervalle de synchronisation",
|
||||||
|
@ -324,6 +324,9 @@
|
|||||||
"Root cert - Tooltip": "Root cert - Tooltip",
|
"Root cert - Tooltip": "Root cert - Tooltip",
|
||||||
"SAML attributes": "SAML attributes",
|
"SAML attributes": "SAML attributes",
|
||||||
"SAML attributes - Tooltip": "SAML attributes - Tooltip",
|
"SAML attributes - Tooltip": "SAML attributes - Tooltip",
|
||||||
|
"SSH cert": "SSH cert",
|
||||||
|
"SSH type": "SSH type",
|
||||||
|
"SSH type - Tooltip": "The auth type of SSH connection",
|
||||||
"Save": "Save",
|
"Save": "Save",
|
||||||
"Save & Exit": "Save & Exit",
|
"Save & Exit": "Save & Exit",
|
||||||
"Session ID": "Session ID",
|
"Session ID": "Session ID",
|
||||||
@ -964,6 +967,10 @@
|
|||||||
"Is read-only": "Is read-only",
|
"Is read-only": "Is read-only",
|
||||||
"Is read-only - Tooltip": "Is read-only - Tooltip",
|
"Is read-only - Tooltip": "Is read-only - Tooltip",
|
||||||
"New Syncer": "New Syncer",
|
"New Syncer": "New Syncer",
|
||||||
|
"SSH host": "SSH host",
|
||||||
|
"SSH password": "SSH password",
|
||||||
|
"SSH port": "SSH port",
|
||||||
|
"SSH user": "SSH user",
|
||||||
"SSL mode": "SSL mode",
|
"SSL mode": "SSL mode",
|
||||||
"SSL mode - Tooltip": "SSL mode - Tooltip",
|
"SSL mode - Tooltip": "SSL mode - Tooltip",
|
||||||
"Sync interval": "Sync interval",
|
"Sync interval": "Sync interval",
|
||||||
|
@ -324,6 +324,9 @@
|
|||||||
"Root cert - Tooltip": "Root cert - Tooltip",
|
"Root cert - Tooltip": "Root cert - Tooltip",
|
||||||
"SAML attributes": "SAML attributes",
|
"SAML attributes": "SAML attributes",
|
||||||
"SAML attributes - Tooltip": "SAML attributes - Tooltip",
|
"SAML attributes - Tooltip": "SAML attributes - Tooltip",
|
||||||
|
"SSH cert": "SSH cert",
|
||||||
|
"SSH type": "SSH type",
|
||||||
|
"SSH type - Tooltip": "The auth type of SSH connection",
|
||||||
"Save": "Menyimpan",
|
"Save": "Menyimpan",
|
||||||
"Save & Exit": "Simpan & Keluar",
|
"Save & Exit": "Simpan & Keluar",
|
||||||
"Session ID": "ID sesi",
|
"Session ID": "ID sesi",
|
||||||
@ -964,6 +967,10 @@
|
|||||||
"Is read-only": "Is read-only",
|
"Is read-only": "Is read-only",
|
||||||
"Is read-only - Tooltip": "Is read-only - Tooltip",
|
"Is read-only - Tooltip": "Is read-only - Tooltip",
|
||||||
"New Syncer": "Sinkronisasi Baru",
|
"New Syncer": "Sinkronisasi Baru",
|
||||||
|
"SSH host": "SSH host",
|
||||||
|
"SSH password": "SSH password",
|
||||||
|
"SSH port": "SSH port",
|
||||||
|
"SSH user": "SSH user",
|
||||||
"SSL mode": "SSL mode",
|
"SSL mode": "SSL mode",
|
||||||
"SSL mode - Tooltip": "SSL mode - Tooltip",
|
"SSL mode - Tooltip": "SSL mode - Tooltip",
|
||||||
"Sync interval": "Interval sinkronisasi",
|
"Sync interval": "Interval sinkronisasi",
|
||||||
|
@ -324,6 +324,9 @@
|
|||||||
"Root cert - Tooltip": "Root cert - Tooltip",
|
"Root cert - Tooltip": "Root cert - Tooltip",
|
||||||
"SAML attributes": "SAML attributes",
|
"SAML attributes": "SAML attributes",
|
||||||
"SAML attributes - Tooltip": "SAML attributes - Tooltip",
|
"SAML attributes - Tooltip": "SAML attributes - Tooltip",
|
||||||
|
"SSH cert": "SSH cert",
|
||||||
|
"SSH type": "SSH type",
|
||||||
|
"SSH type - Tooltip": "The auth type of SSH connection",
|
||||||
"Save": "Save",
|
"Save": "Save",
|
||||||
"Save & Exit": "Save & Exit",
|
"Save & Exit": "Save & Exit",
|
||||||
"Session ID": "Session ID",
|
"Session ID": "Session ID",
|
||||||
@ -964,6 +967,10 @@
|
|||||||
"Is read-only": "Is read-only",
|
"Is read-only": "Is read-only",
|
||||||
"Is read-only - Tooltip": "Is read-only - Tooltip",
|
"Is read-only - Tooltip": "Is read-only - Tooltip",
|
||||||
"New Syncer": "New Syncer",
|
"New Syncer": "New Syncer",
|
||||||
|
"SSH host": "SSH host",
|
||||||
|
"SSH password": "SSH password",
|
||||||
|
"SSH port": "SSH port",
|
||||||
|
"SSH user": "SSH user",
|
||||||
"SSL mode": "SSL mode",
|
"SSL mode": "SSL mode",
|
||||||
"SSL mode - Tooltip": "SSL mode - Tooltip",
|
"SSL mode - Tooltip": "SSL mode - Tooltip",
|
||||||
"Sync interval": "Sync interval",
|
"Sync interval": "Sync interval",
|
||||||
|
@ -324,6 +324,9 @@
|
|||||||
"Root cert - Tooltip": "Root cert - Tooltip",
|
"Root cert - Tooltip": "Root cert - Tooltip",
|
||||||
"SAML attributes": "SAML attributes",
|
"SAML attributes": "SAML attributes",
|
||||||
"SAML attributes - Tooltip": "SAML attributes - Tooltip",
|
"SAML attributes - Tooltip": "SAML attributes - Tooltip",
|
||||||
|
"SSH cert": "SSH cert",
|
||||||
|
"SSH type": "SSH type",
|
||||||
|
"SSH type - Tooltip": "The auth type of SSH connection",
|
||||||
"Save": "保存",
|
"Save": "保存",
|
||||||
"Save & Exit": "保存して終了",
|
"Save & Exit": "保存して終了",
|
||||||
"Session ID": "セッションID",
|
"Session ID": "セッションID",
|
||||||
@ -964,6 +967,10 @@
|
|||||||
"Is read-only": "Is read-only",
|
"Is read-only": "Is read-only",
|
||||||
"Is read-only - Tooltip": "Is read-only - Tooltip",
|
"Is read-only - Tooltip": "Is read-only - Tooltip",
|
||||||
"New Syncer": "新しいシンクロナイザー",
|
"New Syncer": "新しいシンクロナイザー",
|
||||||
|
"SSH host": "SSH host",
|
||||||
|
"SSH password": "SSH password",
|
||||||
|
"SSH port": "SSH port",
|
||||||
|
"SSH user": "SSH user",
|
||||||
"SSL mode": "SSL mode",
|
"SSL mode": "SSL mode",
|
||||||
"SSL mode - Tooltip": "SSL mode - Tooltip",
|
"SSL mode - Tooltip": "SSL mode - Tooltip",
|
||||||
"Sync interval": "同期の間隔",
|
"Sync interval": "同期の間隔",
|
||||||
|
@ -324,6 +324,9 @@
|
|||||||
"Root cert - Tooltip": "Root cert - Tooltip",
|
"Root cert - Tooltip": "Root cert - Tooltip",
|
||||||
"SAML attributes": "SAML attributes",
|
"SAML attributes": "SAML attributes",
|
||||||
"SAML attributes - Tooltip": "SAML attributes - Tooltip",
|
"SAML attributes - Tooltip": "SAML attributes - Tooltip",
|
||||||
|
"SSH cert": "SSH cert",
|
||||||
|
"SSH type": "SSH type",
|
||||||
|
"SSH type - Tooltip": "The auth type of SSH connection",
|
||||||
"Save": "Save",
|
"Save": "Save",
|
||||||
"Save & Exit": "Save & Exit",
|
"Save & Exit": "Save & Exit",
|
||||||
"Session ID": "Session ID",
|
"Session ID": "Session ID",
|
||||||
@ -964,6 +967,10 @@
|
|||||||
"Is read-only": "Is read-only",
|
"Is read-only": "Is read-only",
|
||||||
"Is read-only - Tooltip": "Is read-only - Tooltip",
|
"Is read-only - Tooltip": "Is read-only - Tooltip",
|
||||||
"New Syncer": "New Syncer",
|
"New Syncer": "New Syncer",
|
||||||
|
"SSH host": "SSH host",
|
||||||
|
"SSH password": "SSH password",
|
||||||
|
"SSH port": "SSH port",
|
||||||
|
"SSH user": "SSH user",
|
||||||
"SSL mode": "SSL mode",
|
"SSL mode": "SSL mode",
|
||||||
"SSL mode - Tooltip": "SSL mode - Tooltip",
|
"SSL mode - Tooltip": "SSL mode - Tooltip",
|
||||||
"Sync interval": "Sync interval",
|
"Sync interval": "Sync interval",
|
||||||
|
@ -324,6 +324,9 @@
|
|||||||
"Root cert - Tooltip": "Root cert - Tooltip",
|
"Root cert - Tooltip": "Root cert - Tooltip",
|
||||||
"SAML attributes": "SAML attributes",
|
"SAML attributes": "SAML attributes",
|
||||||
"SAML attributes - Tooltip": "SAML attributes - Tooltip",
|
"SAML attributes - Tooltip": "SAML attributes - Tooltip",
|
||||||
|
"SSH cert": "SSH cert",
|
||||||
|
"SSH type": "SSH type",
|
||||||
|
"SSH type - Tooltip": "The auth type of SSH connection",
|
||||||
"Save": "저장하다",
|
"Save": "저장하다",
|
||||||
"Save & Exit": "저장하고 종료하기",
|
"Save & Exit": "저장하고 종료하기",
|
||||||
"Session ID": "세션 ID",
|
"Session ID": "세션 ID",
|
||||||
@ -964,6 +967,10 @@
|
|||||||
"Is read-only": "Is read-only",
|
"Is read-only": "Is read-only",
|
||||||
"Is read-only - Tooltip": "Is read-only - Tooltip",
|
"Is read-only - Tooltip": "Is read-only - Tooltip",
|
||||||
"New Syncer": "신규 싱크어",
|
"New Syncer": "신규 싱크어",
|
||||||
|
"SSH host": "SSH host",
|
||||||
|
"SSH password": "SSH password",
|
||||||
|
"SSH port": "SSH port",
|
||||||
|
"SSH user": "SSH user",
|
||||||
"SSL mode": "SSL mode",
|
"SSL mode": "SSL mode",
|
||||||
"SSL mode - Tooltip": "SSL mode - Tooltip",
|
"SSL mode - Tooltip": "SSL mode - Tooltip",
|
||||||
"Sync interval": "동기화 간격",
|
"Sync interval": "동기화 간격",
|
||||||
|
@ -324,6 +324,9 @@
|
|||||||
"Root cert - Tooltip": "Root cert - Tooltip",
|
"Root cert - Tooltip": "Root cert - Tooltip",
|
||||||
"SAML attributes": "SAML attributes",
|
"SAML attributes": "SAML attributes",
|
||||||
"SAML attributes - Tooltip": "SAML attributes - Tooltip",
|
"SAML attributes - Tooltip": "SAML attributes - Tooltip",
|
||||||
|
"SSH cert": "SSH cert",
|
||||||
|
"SSH type": "SSH type",
|
||||||
|
"SSH type - Tooltip": "The auth type of SSH connection",
|
||||||
"Save": "Save",
|
"Save": "Save",
|
||||||
"Save & Exit": "Save & Exit",
|
"Save & Exit": "Save & Exit",
|
||||||
"Session ID": "Session ID",
|
"Session ID": "Session ID",
|
||||||
@ -964,6 +967,10 @@
|
|||||||
"Is read-only": "Is read-only",
|
"Is read-only": "Is read-only",
|
||||||
"Is read-only - Tooltip": "Is read-only - Tooltip",
|
"Is read-only - Tooltip": "Is read-only - Tooltip",
|
||||||
"New Syncer": "New Syncer",
|
"New Syncer": "New Syncer",
|
||||||
|
"SSH host": "SSH host",
|
||||||
|
"SSH password": "SSH password",
|
||||||
|
"SSH port": "SSH port",
|
||||||
|
"SSH user": "SSH user",
|
||||||
"SSL mode": "SSL mode",
|
"SSL mode": "SSL mode",
|
||||||
"SSL mode - Tooltip": "SSL mode - Tooltip",
|
"SSL mode - Tooltip": "SSL mode - Tooltip",
|
||||||
"Sync interval": "Sync interval",
|
"Sync interval": "Sync interval",
|
||||||
|
@ -324,6 +324,9 @@
|
|||||||
"Root cert - Tooltip": "Root cert - Tooltip",
|
"Root cert - Tooltip": "Root cert - Tooltip",
|
||||||
"SAML attributes": "SAML attributes",
|
"SAML attributes": "SAML attributes",
|
||||||
"SAML attributes - Tooltip": "SAML attributes - Tooltip",
|
"SAML attributes - Tooltip": "SAML attributes - Tooltip",
|
||||||
|
"SSH cert": "SSH cert",
|
||||||
|
"SSH type": "SSH type",
|
||||||
|
"SSH type - Tooltip": "The auth type of SSH connection",
|
||||||
"Save": "Save",
|
"Save": "Save",
|
||||||
"Save & Exit": "Save & Exit",
|
"Save & Exit": "Save & Exit",
|
||||||
"Session ID": "Session ID",
|
"Session ID": "Session ID",
|
||||||
@ -964,6 +967,10 @@
|
|||||||
"Is read-only": "Is read-only",
|
"Is read-only": "Is read-only",
|
||||||
"Is read-only - Tooltip": "Is read-only - Tooltip",
|
"Is read-only - Tooltip": "Is read-only - Tooltip",
|
||||||
"New Syncer": "New Syncer",
|
"New Syncer": "New Syncer",
|
||||||
|
"SSH host": "SSH host",
|
||||||
|
"SSH password": "SSH password",
|
||||||
|
"SSH port": "SSH port",
|
||||||
|
"SSH user": "SSH user",
|
||||||
"SSL mode": "SSL mode",
|
"SSL mode": "SSL mode",
|
||||||
"SSL mode - Tooltip": "SSL mode - Tooltip",
|
"SSL mode - Tooltip": "SSL mode - Tooltip",
|
||||||
"Sync interval": "Sync interval",
|
"Sync interval": "Sync interval",
|
||||||
|
@ -324,6 +324,9 @@
|
|||||||
"Root cert - Tooltip": "Root cert - Tooltip",
|
"Root cert - Tooltip": "Root cert - Tooltip",
|
||||||
"SAML attributes": "SAML attributes",
|
"SAML attributes": "SAML attributes",
|
||||||
"SAML attributes - Tooltip": "SAML attributes - Tooltip",
|
"SAML attributes - Tooltip": "SAML attributes - Tooltip",
|
||||||
|
"SSH cert": "SSH cert",
|
||||||
|
"SSH type": "SSH type",
|
||||||
|
"SSH type - Tooltip": "The auth type of SSH connection",
|
||||||
"Save": "Save",
|
"Save": "Save",
|
||||||
"Save & Exit": "Save & Exit",
|
"Save & Exit": "Save & Exit",
|
||||||
"Session ID": "Session ID",
|
"Session ID": "Session ID",
|
||||||
@ -964,6 +967,10 @@
|
|||||||
"Is read-only": "Is read-only",
|
"Is read-only": "Is read-only",
|
||||||
"Is read-only - Tooltip": "Is read-only - Tooltip",
|
"Is read-only - Tooltip": "Is read-only - Tooltip",
|
||||||
"New Syncer": "New Syncer",
|
"New Syncer": "New Syncer",
|
||||||
|
"SSH host": "SSH host",
|
||||||
|
"SSH password": "SSH password",
|
||||||
|
"SSH port": "SSH port",
|
||||||
|
"SSH user": "SSH user",
|
||||||
"SSL mode": "SSL mode",
|
"SSL mode": "SSL mode",
|
||||||
"SSL mode - Tooltip": "SSL mode - Tooltip",
|
"SSL mode - Tooltip": "SSL mode - Tooltip",
|
||||||
"Sync interval": "Sync interval",
|
"Sync interval": "Sync interval",
|
||||||
|
@ -324,6 +324,9 @@
|
|||||||
"Root cert - Tooltip": "Root cert - Tooltip",
|
"Root cert - Tooltip": "Root cert - Tooltip",
|
||||||
"SAML attributes": "SAML attributes",
|
"SAML attributes": "SAML attributes",
|
||||||
"SAML attributes - Tooltip": "SAML attributes - Tooltip",
|
"SAML attributes - Tooltip": "SAML attributes - Tooltip",
|
||||||
|
"SSH cert": "SSH cert",
|
||||||
|
"SSH type": "SSH type",
|
||||||
|
"SSH type - Tooltip": "The auth type of SSH connection",
|
||||||
"Save": "Salvar",
|
"Save": "Salvar",
|
||||||
"Save & Exit": "Salvar e Sair",
|
"Save & Exit": "Salvar e Sair",
|
||||||
"Session ID": "ID da sessão",
|
"Session ID": "ID da sessão",
|
||||||
@ -964,6 +967,10 @@
|
|||||||
"Is read-only": "Is read-only",
|
"Is read-only": "Is read-only",
|
||||||
"Is read-only - Tooltip": "Is read-only - Tooltip",
|
"Is read-only - Tooltip": "Is read-only - Tooltip",
|
||||||
"New Syncer": "Novo Syncer",
|
"New Syncer": "Novo Syncer",
|
||||||
|
"SSH host": "SSH host",
|
||||||
|
"SSH password": "SSH password",
|
||||||
|
"SSH port": "SSH port",
|
||||||
|
"SSH user": "SSH user",
|
||||||
"SSL mode": "SSL mode",
|
"SSL mode": "SSL mode",
|
||||||
"SSL mode - Tooltip": "SSL mode - Tooltip",
|
"SSL mode - Tooltip": "SSL mode - Tooltip",
|
||||||
"Sync interval": "Intervalo de sincronização",
|
"Sync interval": "Intervalo de sincronização",
|
||||||
|
@ -324,6 +324,9 @@
|
|||||||
"Root cert - Tooltip": "Root cert - Tooltip",
|
"Root cert - Tooltip": "Root cert - Tooltip",
|
||||||
"SAML attributes": "SAML attributes",
|
"SAML attributes": "SAML attributes",
|
||||||
"SAML attributes - Tooltip": "SAML attributes - Tooltip",
|
"SAML attributes - Tooltip": "SAML attributes - Tooltip",
|
||||||
|
"SSH cert": "SSH cert",
|
||||||
|
"SSH type": "SSH type",
|
||||||
|
"SSH type - Tooltip": "The auth type of SSH connection",
|
||||||
"Save": "Сохранить",
|
"Save": "Сохранить",
|
||||||
"Save & Exit": "Сохранить и выйти",
|
"Save & Exit": "Сохранить и выйти",
|
||||||
"Session ID": "Идентификатор сессии",
|
"Session ID": "Идентификатор сессии",
|
||||||
@ -964,6 +967,10 @@
|
|||||||
"Is read-only": "Is read-only",
|
"Is read-only": "Is read-only",
|
||||||
"Is read-only - Tooltip": "Is read-only - Tooltip",
|
"Is read-only - Tooltip": "Is read-only - Tooltip",
|
||||||
"New Syncer": "Новый синхронизатор",
|
"New Syncer": "Новый синхронизатор",
|
||||||
|
"SSH host": "SSH host",
|
||||||
|
"SSH password": "SSH password",
|
||||||
|
"SSH port": "SSH port",
|
||||||
|
"SSH user": "SSH user",
|
||||||
"SSL mode": "SSL mode",
|
"SSL mode": "SSL mode",
|
||||||
"SSL mode - Tooltip": "SSL mode - Tooltip",
|
"SSL mode - Tooltip": "SSL mode - Tooltip",
|
||||||
"Sync interval": "Интервал синхронизации",
|
"Sync interval": "Интервал синхронизации",
|
||||||
|
@ -324,6 +324,9 @@
|
|||||||
"Root cert - Tooltip": "Root cert - Tooltip",
|
"Root cert - Tooltip": "Root cert - Tooltip",
|
||||||
"SAML attributes": "SAML attributes",
|
"SAML attributes": "SAML attributes",
|
||||||
"SAML attributes - Tooltip": "SAML attributes - Tooltip",
|
"SAML attributes - Tooltip": "SAML attributes - Tooltip",
|
||||||
|
"SSH cert": "SSH cert",
|
||||||
|
"SSH type": "SSH type",
|
||||||
|
"SSH type - Tooltip": "The auth type of SSH connection",
|
||||||
"Save": "Save",
|
"Save": "Save",
|
||||||
"Save & Exit": "Save & Exit",
|
"Save & Exit": "Save & Exit",
|
||||||
"Session ID": "Session ID",
|
"Session ID": "Session ID",
|
||||||
@ -964,6 +967,10 @@
|
|||||||
"Is read-only": "Is read-only",
|
"Is read-only": "Is read-only",
|
||||||
"Is read-only - Tooltip": "Is read-only - Tooltip",
|
"Is read-only - Tooltip": "Is read-only - Tooltip",
|
||||||
"New Syncer": "New Syncer",
|
"New Syncer": "New Syncer",
|
||||||
|
"SSH host": "SSH host",
|
||||||
|
"SSH password": "SSH password",
|
||||||
|
"SSH port": "SSH port",
|
||||||
|
"SSH user": "SSH user",
|
||||||
"SSL mode": "SSL mode",
|
"SSL mode": "SSL mode",
|
||||||
"SSL mode - Tooltip": "SSL mode - Tooltip",
|
"SSL mode - Tooltip": "SSL mode - Tooltip",
|
||||||
"Sync interval": "Sync interval",
|
"Sync interval": "Sync interval",
|
||||||
|
@ -324,6 +324,9 @@
|
|||||||
"Root cert - Tooltip": "Root cert - Tooltip",
|
"Root cert - Tooltip": "Root cert - Tooltip",
|
||||||
"SAML attributes": "SAML attributes",
|
"SAML attributes": "SAML attributes",
|
||||||
"SAML attributes - Tooltip": "SAML attributes - Tooltip",
|
"SAML attributes - Tooltip": "SAML attributes - Tooltip",
|
||||||
|
"SSH cert": "SSH cert",
|
||||||
|
"SSH type": "SSH type",
|
||||||
|
"SSH type - Tooltip": "The auth type of SSH connection",
|
||||||
"Save": "Kaydet",
|
"Save": "Kaydet",
|
||||||
"Save & Exit": "Kaydet ve Çık",
|
"Save & Exit": "Kaydet ve Çık",
|
||||||
"Session ID": "Oturum ID",
|
"Session ID": "Oturum ID",
|
||||||
@ -964,6 +967,10 @@
|
|||||||
"Is read-only": "Is read-only",
|
"Is read-only": "Is read-only",
|
||||||
"Is read-only - Tooltip": "Is read-only - Tooltip",
|
"Is read-only - Tooltip": "Is read-only - Tooltip",
|
||||||
"New Syncer": "New Syncer",
|
"New Syncer": "New Syncer",
|
||||||
|
"SSH host": "SSH host",
|
||||||
|
"SSH password": "SSH password",
|
||||||
|
"SSH port": "SSH port",
|
||||||
|
"SSH user": "SSH user",
|
||||||
"SSL mode": "SSL mode",
|
"SSL mode": "SSL mode",
|
||||||
"SSL mode - Tooltip": "SSL mode - Tooltip",
|
"SSL mode - Tooltip": "SSL mode - Tooltip",
|
||||||
"Sync interval": "Sync interval",
|
"Sync interval": "Sync interval",
|
||||||
|
@ -324,6 +324,9 @@
|
|||||||
"Root cert - Tooltip": "Root cert - Tooltip",
|
"Root cert - Tooltip": "Root cert - Tooltip",
|
||||||
"SAML attributes": "SAML attributes",
|
"SAML attributes": "SAML attributes",
|
||||||
"SAML attributes - Tooltip": "SAML attributes - Tooltip",
|
"SAML attributes - Tooltip": "SAML attributes - Tooltip",
|
||||||
|
"SSH cert": "SSH cert",
|
||||||
|
"SSH type": "SSH type",
|
||||||
|
"SSH type - Tooltip": "The auth type of SSH connection",
|
||||||
"Save": "Save",
|
"Save": "Save",
|
||||||
"Save & Exit": "Save & Exit",
|
"Save & Exit": "Save & Exit",
|
||||||
"Session ID": "Session ID",
|
"Session ID": "Session ID",
|
||||||
@ -964,6 +967,10 @@
|
|||||||
"Is read-only": "Is read-only",
|
"Is read-only": "Is read-only",
|
||||||
"Is read-only - Tooltip": "Is read-only - Tooltip",
|
"Is read-only - Tooltip": "Is read-only - Tooltip",
|
||||||
"New Syncer": "New Syncer",
|
"New Syncer": "New Syncer",
|
||||||
|
"SSH host": "SSH host",
|
||||||
|
"SSH password": "SSH password",
|
||||||
|
"SSH port": "SSH port",
|
||||||
|
"SSH user": "SSH user",
|
||||||
"SSL mode": "SSL mode",
|
"SSL mode": "SSL mode",
|
||||||
"SSL mode - Tooltip": "SSL mode - Tooltip",
|
"SSL mode - Tooltip": "SSL mode - Tooltip",
|
||||||
"Sync interval": "Sync interval",
|
"Sync interval": "Sync interval",
|
||||||
|
@ -324,6 +324,9 @@
|
|||||||
"Root cert - Tooltip": "Root cert - Tooltip",
|
"Root cert - Tooltip": "Root cert - Tooltip",
|
||||||
"SAML attributes": "SAML attributes",
|
"SAML attributes": "SAML attributes",
|
||||||
"SAML attributes - Tooltip": "SAML attributes - Tooltip",
|
"SAML attributes - Tooltip": "SAML attributes - Tooltip",
|
||||||
|
"SSH cert": "SSH cert",
|
||||||
|
"SSH type": "SSH type",
|
||||||
|
"SSH type - Tooltip": "The auth type of SSH connection",
|
||||||
"Save": "Lưu",
|
"Save": "Lưu",
|
||||||
"Save & Exit": "Lưu và Thoát",
|
"Save & Exit": "Lưu và Thoát",
|
||||||
"Session ID": "ID phiên làm việc",
|
"Session ID": "ID phiên làm việc",
|
||||||
@ -964,6 +967,10 @@
|
|||||||
"Is read-only": "Is read-only",
|
"Is read-only": "Is read-only",
|
||||||
"Is read-only - Tooltip": "Is read-only - Tooltip",
|
"Is read-only - Tooltip": "Is read-only - Tooltip",
|
||||||
"New Syncer": "New Syncer: Đồng bộ mới",
|
"New Syncer": "New Syncer: Đồng bộ mới",
|
||||||
|
"SSH host": "SSH host",
|
||||||
|
"SSH password": "SSH password",
|
||||||
|
"SSH port": "SSH port",
|
||||||
|
"SSH user": "SSH user",
|
||||||
"SSL mode": "SSL mode",
|
"SSL mode": "SSL mode",
|
||||||
"SSL mode - Tooltip": "SSL mode - Tooltip",
|
"SSL mode - Tooltip": "SSL mode - Tooltip",
|
||||||
"Sync interval": "Khoảng thời gian đồng bộ hóa",
|
"Sync interval": "Khoảng thời gian đồng bộ hóa",
|
||||||
|
@ -324,6 +324,9 @@
|
|||||||
"Root cert - Tooltip": "根证书",
|
"Root cert - Tooltip": "根证书",
|
||||||
"SAML attributes": "SAML属性",
|
"SAML attributes": "SAML属性",
|
||||||
"SAML attributes - Tooltip": "Casdoor作为SAML IdP时所返回的SAML响应的属性",
|
"SAML attributes - Tooltip": "Casdoor作为SAML IdP时所返回的SAML响应的属性",
|
||||||
|
"SSH cert": "SSH证书",
|
||||||
|
"SSH type": "SSH类型",
|
||||||
|
"SSH type - Tooltip": "SSH连接的认证类型",
|
||||||
"Save": "保存",
|
"Save": "保存",
|
||||||
"Save & Exit": "保存 & 退出",
|
"Save & Exit": "保存 & 退出",
|
||||||
"Session ID": "会话ID",
|
"Session ID": "会话ID",
|
||||||
@ -964,6 +967,10 @@
|
|||||||
"Is read-only": "是否只读",
|
"Is read-only": "是否只读",
|
||||||
"Is read-only - Tooltip": "只读",
|
"Is read-only - Tooltip": "只读",
|
||||||
"New Syncer": "添加同步器",
|
"New Syncer": "添加同步器",
|
||||||
|
"SSH host": "SSH主机",
|
||||||
|
"SSH password": "SSH密码",
|
||||||
|
"SSH port": "SSH端口",
|
||||||
|
"SSH user": "SSH用户",
|
||||||
"SSL mode": "SSL模式",
|
"SSL mode": "SSL模式",
|
||||||
"SSL mode - Tooltip": "连接数据库采用哪种SSL模式",
|
"SSL mode - Tooltip": "连接数据库采用哪种SSL模式",
|
||||||
"Sync interval": "同步间隔",
|
"Sync interval": "同步间隔",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user