Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 24 additions & 25 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -138,23 +138,21 @@ The configuration file is a JSON array of objects. Each object defines a tunnel.
"authType": "KEY",
"password": "",
"key": "/etc/autossh/id_rsa",
"passphrase": "passphrase",
"passphrase": "passphrase-in-base64",
"jump": {
"host": "jump-1-ip",
"port": 22,
"username": "user",
"username": "user1",
"authType": "KEY",
"password": "",
"key": "/etc/autossh/id_rsa",
"passphrase": "passphrase",
"passphrase": "passphrase-in-base64",
"jump": {
"host": "jump-2-ip",
"port": 22,
"username": "user",
"authType": "KEY",
"password": "",
"key": "/etc/autossh/id_rsa",
"passphrase": "passphrase"
"username": "user2",
"authType": "PASS",
"password": "password-in-base64"
}
}
}
Expand All @@ -164,23 +162,23 @@ The configuration file is a JSON array of objects. Each object defines a tunnel.

### Fields Description

| Field | Type | Required | Description |
|-----------------|----------------|----------|-----------------------------------------------------------------------------|
| `name` | string | ✅ | Identifier for the tunnel. |
| `type` | string | ✅ | Tunnel type: `L` for remote → local, `R` for local → remote. |
| `localPort` | number | ✅ | Port on the local machine. |
| `localHost` | string | ✅ | Local host IP or `0.0.0.0` to bind all interfaces. |
| `remotePort` | number | ✅ | Port on the remote machine. |
| `remoteHost` | string | ✅ | Remote host IP or `0.0.0.0`. |
| `server` | object | ✅ | Final destination SSH server configuration. |
| `server.host` | string | ✅ | SSH server IP or hostname. |
| `server.port` | number | ✅ | SSH server port, usually 22. |
| `server.username` | string | ✅ | SSH username. |
| `server.authType` | string | ✅ | Authentication type: `KEY` or `PASS`. |
| `server.key` | string | 🔹 | Path to SSH key file if `authType` is `KEY`. |
| `server.password` | string | 🔹 | Password if `authType` is `PASS`. |
| `server.passphrase` | string | 🔹 | Passphrase for the SSH key if required. |
| `server.jump` | object/null | - | Optional jump host configuration (recursive structure). |
| Field | Type | Required | Description |
|-----------------|--------------------|----------|-----------------------------------------------------------------------------|
| `name` | string | ✅ | Identifier for the tunnel. |
| `type` | string | ✅ | Tunnel type: `L` for remote → local, `R` for local → remote. |
| `localPort` | number | ✅ | Port on the local machine. |
| `localHost` | string | ✅ | Local host IP or `0.0.0.0` to bind all interfaces. |
| `remotePort` | number | ✅ | Port on the remote machine. |
| `remoteHost` | string | ✅ | Remote host IP or `0.0.0.0`. |
| `server` | object | ✅ | Final destination SSH server configuration. |
| `server.host` | string | ✅ | SSH server IP or hostname. |
| `server.port` | number | ✅ | SSH server port, usually 22. |
| `server.username` | string | ✅ | SSH username. |
| `server.authType` | string | ✅ | Authentication type: `KEY` or `PASS`. |
| `server.key` | string | 🔹 | Path to SSH key file if `authType` is `KEY`. |
| `server.password` | string(base64) | 🔹 | Password if `authType` is `PASS`. |
| `server.passphrase` | string(base64) | 🔹 | Passphrase for the SSH key if required. |
| `server.jump` | object/null | - | Optional jump host configuration (recursive structure). |

> **Note:** Jump hosts are optional and can be nested multiple times.

Expand All @@ -203,6 +201,7 @@ The configuration file is a JSON array of objects. Each object defines a tunnel.
- **D:** Remote service (MongoDB, PostgreSQL, etc.)

### Authentication Flow
Authentication for Passphrase or Password both should be base64 encoded.
1. **KEY authentication**
- Uses a private key (`key`) and optional `passphrase`.
2. **Password authentication**
Expand Down
8 changes: 7 additions & 1 deletion main.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,13 @@ func main() {
Name: "telepath",
Version: AppVersion,
Description: "telepath is a cli application to forward port securly.",
Usage: "The secure tunneling tools.",
Flags: []cli.Flag{
&cli.StringFlag{
Name: "config-file",
Aliases: []string{"f"},
Usage: "accepts config file path.",
Required: true,
Required: false,
Destination: &configPath,
},
&cli.BoolFlag{
Expand All @@ -49,6 +50,10 @@ func main() {
},
},
Action: func(ctx *cli.Context) error {
if len(configPath) == 0 {
fmt.Println(`Required flag "--config-file" or "-f" not set.`)
return nil
}
cfgs, err := services.ParseConfig(configPath)
if err != nil {
return err
Expand All @@ -72,6 +77,7 @@ func main() {
signal.Notify(sigCh, os.Interrupt, syscall.SIGTERM)
go func() {
sig := <-sigCh
fmt.Println("\r\033[K")
log.Printf("Received signal %s, shutting down gracefully...", sig)
cancel()
}()
Expand Down
8 changes: 6 additions & 2 deletions services/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (

"github.com/tech-thinker/telepath/constants"
"github.com/tech-thinker/telepath/models"
"github.com/tech-thinker/telepath/utils"
"golang.org/x/crypto/ssh"
)

Expand Down Expand Up @@ -292,7 +293,8 @@ func (s *srv) createSSHClient(server *models.Server, proxy *ssh.Client) (*ssh.Cl
var authMethods []ssh.AuthMethod

if server.AuthType == constants.CREDIENTIAL_PASS {
authMethods = append(authMethods, ssh.Password(server.Password))
password := utils.Base64Decode(server.Password)
authMethods = append(authMethods, ssh.Password(password))
}

if server.AuthType == constants.CREDIENTIAL_KEY {
Expand All @@ -301,8 +303,10 @@ func (s *srv) createSSHClient(server *models.Server, proxy *ssh.Client) (*ssh.Cl
return nil, fmt.Errorf("failed to read key file: %w", err)
}
var signer ssh.Signer

if len(server.Passphrase) > 0 {
signer, err = ssh.ParsePrivateKeyWithPassphrase(key, []byte(server.Passphrase))
passphrase := utils.Base64Decode(server.Passphrase)
signer, err = ssh.ParsePrivateKeyWithPassphrase(key, []byte(passphrase))
} else {
signer, err = ssh.ParsePrivateKey(key)
}
Expand Down
15 changes: 15 additions & 0 deletions utils/encoding.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package utils

import "encoding/base64"

func Base64Encode(plain string) string {
return base64.StdEncoding.EncodeToString([]byte(plain))
}

func Base64Decode(cipher string) string {
data, err := base64.StdEncoding.DecodeString(cipher)
if err != nil {
return ""
}
return string(data)
}
Loading