Compare commits
	
		
			7 Commits
		
	
	
		
			2817417eca
			...
			v0.0.1
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 1d292ec21a | |||
| ee828c3e24 | |||
| a9fdf0a053 | |||
| ca02d9b609 | |||
| 792dfdba78 | |||
| 4f7a8f0b04 | |||
| 6d6ed30227 | 
							
								
								
									
										70
									
								
								.goreleaser.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								.goreleaser.yaml
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										25
									
								
								.woodpecker.yml
									
									
									
									
									
										Normal 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 | ||||
| @@ -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>  | ||||
| <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> | ||||
|  | ||||
| --- | ||||
|   | ||||
| @@ -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 { | ||||
|   | ||||
| @@ -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 | ||||
| @@ -63,6 +64,17 @@ func Docker(route config.Route) router.Handler { | ||||
| 			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(), | ||||
| 			client.WithVersionFromEnv(), | ||||
| @@ -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) | ||||
|   | ||||
| @@ -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 | ||||
| @@ -78,6 +79,11 @@ func Proxy(route config.Route) router.Handler { | ||||
| 			} | ||||
| 		} | ||||
| 		 | ||||
| 		if opts.Port == nil { | ||||
| 			port := uint(22) | ||||
| 			opts.Port = &port | ||||
| 		} | ||||
|  | ||||
| 		auth := goph.Auth{ | ||||
| 			gossh.PasswordCallback(requestPassword(opts, sess)), | ||||
| 		} | ||||
| @@ -96,24 +102,26 @@ func Proxy(route config.Route) router.Handler { | ||||
| 			auth = append(goph.Auth{gossh.PublicKeys(pk)}, auth...) | ||||
| 		} | ||||
|  | ||||
| 		c, err := goph.New(*opts.User, opts.Server, auth) | ||||
| 		if err != nil { | ||||
| 		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 | ||||
| 					} | ||||
|  | ||||
| 		knownHostHandler, err := goph.DefaultKnownHosts() | ||||
| 		if err != nil { | ||||
| 				} else 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, "") | ||||
| 				return nil | ||||
| 			}, | ||||
| 		}) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 			return knownHostHandler(host, remote, key) | ||||
| 		} | ||||
|  | ||||
| 		baseCmd := sess.Command() | ||||
|  | ||||
|   | ||||
							
								
								
									
										11
									
								
								seashell.service
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								seashell.service
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | ||||
| [Unit] | ||||
| Description=Seashell SSH Server | ||||
| After=network.target | ||||
|  | ||||
| [Service] | ||||
| ExecStart=seashell | ||||
| Restart=always | ||||
| StandardOutput=journal | ||||
|  | ||||
| [Install] | ||||
| WantedBy=default.target | ||||
		Reference in New Issue
	
	Block a user