Compare commits

..

7 Commits

Author SHA1 Message Date
1d292ec21a Fix CI settings
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
ci/woodpecker/release/woodpecker Pipeline was successful
ci/woodpecker/tag/woodpecker Pipeline was successful
2024-08-08 14:54:22 -07:00
ee828c3e24 Switch to Ko for building docker images
Some checks failed
ci/woodpecker/push/woodpecker Pipeline was successful
ci/woodpecker/tag/woodpecker Pipeline failed
2024-08-08 14:49:09 -07:00
a9fdf0a053 Add CI configuration
Some checks failed
ci/woodpecker/push/woodpecker Pipeline was successful
ci/woodpecker/tag/woodpecker Pipeline failed
2024-08-08 14:34:42 -07:00
ca02d9b609 Fix known hosts handling in proxy backend 2024-08-04 19:49:43 -07:00
792dfdba78 Add user_map setting to docker backend 2024-08-04 18:27:21 -07:00
4f7a8f0b04 Rename userMap to user_map for consistency 2024-08-04 18:25:20 -07:00
6d6ed30227 Add README badges 2024-08-04 23:45:25 +00:00
7 changed files with 145 additions and 35 deletions

70
.goreleaser.yaml Normal file
View File

@@ -0,0 +1,70 @@
before:
hooks:
- go mod tidy
builds:
- id: seashell
env:
- CGO_ENABLED=0
binary: seashell
goos:
- linux
goarch:
- amd64
- "386"
- arm64
- arm
- riscv64
archives:
- files:
- seashell.service
nfpms:
- id: seashell
description: "SSH server with virtual hosts and username-based routing"
homepage: 'https://gitea.elara.ws/Elara6331/seashell'
maintainer: 'Elara Ivy <elara@elara.ws>'
license: AGPLv3
formats:
- deb
- rpm
- apk
- archlinux
provides:
- seashell
conflicts:
- seashell
contents:
- src: seashell.service
dst: /etc/systemd/system/seashell.service
aurs:
- name: seashell-bin
description: "SSH server with virtual hosts and username-based routing"
homepage: 'https://gitea.elara.ws/Elara6331/seashell'
maintainers:
- 'Elara Ivy <elara@elara.ws>'
license: AGPLv3
private_key: '{{ .Env.AUR_KEY }}'
git_url: 'ssh://aur@aur.archlinux.org/seashell-bin.git'
provides:
- seashell
conflicts:
- seashell
package: |-
# binaries
install -Dm755 ./seashell "${pkgdir}/usr/bin/seashell"
# services
install -Dm644 ./seashell.service "${pkgdir}/etc/systemd/system/seashell.service"
release:
gitea:
owner: Elara6331
name: seashell
gitea_urls:
api: 'https://gitea.elara.ws/api/v1/'
download: 'https://gitea.elara.ws'
skip_tls_verify: false
checksum:
name_template: 'checksums.txt'
snapshot:
name_template: "{{ incpatch .Version }}-next"
changelog:
sort: asc

25
.woodpecker.yml Normal file
View File

@@ -0,0 +1,25 @@
labels:
platform: linux/amd64
steps:
docker:
image: gitea.elara.ws/elara6331/builder
environment:
- REGISTRY=gitea.elara.ws
- REGISTRY_USERNAME=Elara6331
- KO_DOCKER_REPO=gitea.elara.ws/elara6331
- KO_DEFAULTBASEIMAGE=gitea.elara.ws/elara6331/static
secrets: [ registry_password ]
commands:
- registry-login
- ko build -B --platform=linux/amd64,linux/arm64,linux/riscv64 -t latest,${CI_COMMIT_TAG} --sbom=none
when:
event: tag
release:
image: goreleaser/goreleaser
commands:
- goreleaser release
secrets: [ gitea_token, aur_key ]
when:
event: tag

View File

@@ -1,5 +1,7 @@
<p align="center">
<img src="assets/seashell-text.svg" width="250">
<img src="assets/seashell-text.svg" width="250" alt="Seashell logo"><br><br>
<a href="https://goreportcard.com/report/go.elara.ws/seashell"><img src="https://goreportcard.com/badge/go.elara.ws/seashell?style=for-the-badge" alt="Go Report Card"></a>&nbsp;
<a href="https://gitea.elara.ws/Elara6331/seashell/wiki/Home"><img src="https://img.shields.io/badge/read%20the-docs-purple?style=for-the-badge" alt="Read the Docs"></a>
</p>
---

View File

@@ -22,8 +22,6 @@
package backends
import (
"strings"
"github.com/zclconf/go-cty/cty"
"go.elara.ws/seashell/internal/config"
"go.elara.ws/seashell/internal/router"
@@ -84,17 +82,6 @@ func ctyObjToStringMap(o *cty.Value) map[string]string {
return out
}
// sshGetenv gets an environment variable from the SSH session
func sshGetenv(env []string, key string) string {
for _, kv := range env {
before, after, ok := strings.Cut(kv, "=")
if ok && before == key {
return after
}
}
return ""
}
// valueOr returns the value that v points to
// or a default value if v is nil.
func valueOr[T any](v *T, or T) T {

View File

@@ -41,6 +41,7 @@ type dockerSettings struct {
Command *cty.Value `cty:"command"`
Privileged *bool `cty:"privileged"`
User *string `cty:"user"`
UserMap *cty.Value `cty:"user_map"`
}
// Docker is the docker backend. It returns a handler that connects
@@ -62,6 +63,17 @@ func Docker(route config.Route) router.Handler {
if !ok {
return errors.New("this route only accepts pty sessions (try adding the -t flag)")
}
if opts.User == nil {
userMap := ctyObjToStringMap(opts.UserMap)
user, _ := sshctx.GetUser(sess.Context())
if muser, ok := userMap[user.Name]; ok {
opts.User = &muser
} else {
opts.User = &user.Name
}
}
c, err := client.NewClientWithOpts(
client.WithHostFromEnv(),
@@ -72,11 +84,6 @@ func Docker(route config.Route) router.Handler {
return err
}
if opts.User == nil {
envUser := sshGetenv(sess.Environ(), "DOCKER_USER")
opts.User = &envUser
}
cmd := sess.Command()
if len(cmd) == 0 {
cmd = ctyTupleToStrings(opts.Command)

View File

@@ -42,9 +42,10 @@ import (
// proxySettings represents settings for the proxy backend.
type proxySettings struct {
Server string `cty:"server"`
Port *uint `cty:"port"`
User *string `cty:"user"`
PrivkeyPath *string `cty:"privkey"`
UserMap *cty.Value `cty:"userMap"`
UserMap *cty.Value `cty:"user_map"`
}
// Proxy is the proxy backend. It returns a handler that establishes a proxy
@@ -77,6 +78,11 @@ func Proxy(route config.Route) router.Handler {
opts.User = &user.Name
}
}
if opts.Port == nil {
port := uint(22)
opts.Port = &port
}
auth := goph.Auth{
gossh.PasswordCallback(requestPassword(opts, sess)),
@@ -96,25 +102,27 @@ func Proxy(route config.Route) router.Handler {
auth = append(goph.Auth{gossh.PublicKeys(pk)}, auth...)
}
c, err := goph.New(*opts.User, opts.Server, auth)
c, err := goph.NewConn(&goph.Config{
Auth: auth,
User: *opts.User,
Addr: opts.Server,
Port: *opts.Port,
Callback: func(host string, remote net.Addr, key gossh.PublicKey) error {
found, err := goph.CheckKnownHost(host, remote, key, "")
if !found {
if err = goph.AddKnownHost(host, remote, key, ""); err != nil {
return err
}
} else if err != nil {
return err
}
return nil
},
})
if err != nil {
return err
}
knownHostHandler, err := goph.DefaultKnownHosts()
if err != nil {
return err
}
c.Config.Callback = func(host string, remote net.Addr, key gossh.PublicKey) error {
println("hi")
err = goph.AddKnownHost(host, remote, key, "")
if err != nil {
return err
}
return knownHostHandler(host, remote, key)
}
baseCmd := sess.Command()
var userCmd string

11
seashell.service Normal file
View File

@@ -0,0 +1,11 @@
[Unit]
Description=Seashell SSH Server
After=network.target
[Service]
ExecStart=seashell
Restart=always
StandardOutput=journal
[Install]
WantedBy=default.target