diff --git a/README.md b/README.md index 7c5b608..c6979c1 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# sqls +# sqls: SQL Language Server ![test](https://github.com/sqls-server/sqls/workflows/test/badge.svg) @@ -222,7 +222,7 @@ require'lspconfig'.sqls.setup{ **I'm sorry. Please wait a little longer for other editor settings.** -### Configuration Params +### Configuration Parameters The first setting in `connections` is the default connection. diff --git a/go.mod b/go.mod index 23b2ec0..7c9ed6f 100644 --- a/go.mod +++ b/go.mod @@ -9,6 +9,7 @@ require ( github.com/godror/godror v0.41.0 github.com/google/go-cmp v0.5.9 github.com/jackc/pgx/v4 v4.18.1 + github.com/jfcote87/sshdb v0.5.3 github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88 // indirect github.com/sourcegraph/jsonrpc2 v0.2.0 github.com/urfave/cli/v2 v2.27.0 diff --git a/go.sum b/go.sum index c6cfdbc..180aebc 100644 --- a/go.sum +++ b/go.sum @@ -88,6 +88,7 @@ github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9 github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= github.com/jackc/chunkreader/v2 v2.0.1 h1:i+RDz65UE+mmpjTfyz0MoVTnzeYxroil2G82ki7MGG8= github.com/jackc/chunkreader/v2 v2.0.1/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= +github.com/jackc/fake v0.0.0-20150926172116-812a484cc733/go.mod h1:WrMFNQdiFJ80sQsxDoMokWK1W5TQtxBFNpzWTD84ibQ= github.com/jackc/pgconn v0.0.0-20190420214824-7e0022ef6ba3/go.mod h1:jkELnwuX+w9qN5YIfX0fl88Ehu4XC3keFuOJJk9pcnA= github.com/jackc/pgconn v0.0.0-20190824142844-760dd75542eb/go.mod h1:lLjNuW/+OfW9/pnVKPazfWOgNfH2aPem8YQ7ilXGvJE= github.com/jackc/pgconn v0.0.0-20190831204454-2fabfa3c18b7/go.mod h1:ZJKsE/KZfsUgOEh9hBm+xYTstcNHg7UPMVJqRfQxq4s= @@ -135,6 +136,8 @@ github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0f github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v1.3.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jfcote87/sshdb v0.5.3 h1:c0I3+ScEbT0mjvpoY8qbVNfR4Y9Q5JWh52WnmjfsuV0= +github.com/jfcote87/sshdb v0.5.3/go.mod h1:YIGPRF3vtRG1Cvpwa1LaQvmrsIEPKC9WqF+ZU5rInUw= github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901 h1:rp+c0RAYOWj8l6qbCUTSiRLG/iKnW3K3/QfPPuSsBt4= github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901/go.mod h1:Z86h9688Y0wesXCyonoVr47MasHilkuLMqGhRZ4Hpak= github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88 h1:uC1QfSlInpQF+M0ao65imhwqKnz3Q2z/d8PWZRMQvDM= @@ -370,7 +373,6 @@ google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQ google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I= google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s= diff --git a/internal/database/mssql.go b/internal/database/mssql.go index 60611f2..dd795ab 100644 --- a/internal/database/mssql.go +++ b/internal/database/mssql.go @@ -1,6 +1,7 @@ package database import ( + "os" "context" "database/sql" "fmt" @@ -10,6 +11,8 @@ import ( _ "github.com/denisenkom/go-mssqldb" "github.com/sqls-server/sqls/dialect" + "github.com/jfcote87/sshdb" + "github.com/jfcote87/sshdb/mssql" "golang.org/x/crypto/ssh" ) @@ -21,7 +24,6 @@ func init() { func mssqlOpen(dbConnCfg *DBConfig) (*DBConnection, error) { var ( conn *sql.DB - sshConn *ssh.Client ) dsn, err := genMssqlConfig(dbConnCfg) if err != nil { @@ -29,13 +31,44 @@ func mssqlOpen(dbConnCfg *DBConfig) (*DBConnection, error) { } if dbConnCfg.SSHCfg != nil { - return nil, fmt.Errorf("connect via SSH is not supported") - } - dbConn, err := sql.Open("sqlserver", dsn) - if err != nil { - return nil, err + key, err := os.ReadFile(dbConnCfg.SSHCfg.PrivateKey) + if err != nil { + return nil, fmt.Errorf("unable to open private key") + } + + signer, err := ssh.ParsePrivateKeyWithPassphrase(key, []byte(dbConnCfg.SSHCfg.PassPhrase)) + if err != nil { + return nil, fmt.Errorf("unable to decrypt private key") + } + + cfg := &ssh.ClientConfig { + User: dbConnCfg.SSHCfg.User, + Auth: []ssh.AuthMethod { + ssh.PublicKeys(signer), + }, + HostKeyCallback: ssh.InsecureIgnoreHostKey(), + } + + remoteAddr := fmt.Sprintf("%s:%d", dbConnCfg.SSHCfg.Host, dbConnCfg.SSHCfg.Port) + + tunnel, err := sshdb.New(cfg, remoteAddr) + if err != nil { + return nil, fmt.Errorf("%w", err) + } + + connector, err := tunnel.OpenConnector(mssql.TunnelDriver, dsn) + if err != nil { + return nil, err + } + + conn = sql.OpenDB(connector) + } else { + conn, err = sql.Open("mssql", dsn) + if err != nil { + return nil, err + } } - conn = dbConn + if err = conn.Ping(); err != nil { return nil, err } @@ -45,7 +78,6 @@ func mssqlOpen(dbConnCfg *DBConfig) (*DBConnection, error) { return &DBConnection{ Conn: conn, - SSHConn: sshConn, }, nil }