From d3e2409c6c6afbb0dcb9038613f314e7ab8d62a2 Mon Sep 17 00:00:00 2001 From: Eric Bower Date: Sat, 18 Jan 2025 08:14:31 -0500 Subject: [PATCH] chore: rm imgs --- .env.example | 19 --- cmd/imgs/ssh/main.go | 9 - cmd/imgs/web/main.go | 7 - docker-compose.override.yml | 30 ---- docker-compose.prod.yml | 60 ------- docker-compose.yml | 24 --- imgs/api.go | 181 -------------------- imgs/cli.go | 275 ------------------------------- imgs/config.go | 35 ---- imgs/registry.yml | 11 -- imgs/ssh.go | 318 ------------------------------------ 11 files changed, 969 deletions(-) delete mode 100644 cmd/imgs/ssh/main.go delete mode 100644 cmd/imgs/web/main.go delete mode 100644 imgs/cli.go delete mode 100644 imgs/config.go delete mode 100644 imgs/registry.yml delete mode 100644 imgs/ssh.go diff --git a/.env.example b/.env.example index 74c1abcc..937c1e7e 100644 --- a/.env.example +++ b/.env.example @@ -66,25 +66,6 @@ PROSE_DOMAIN=prose.dev.pico.sh:3002 PROSE_PROTOCOL=http PROSE_DEBUG=1 -IMGS_CADDYFILE=./caddy/Caddyfile -IMGS_V4= -IMGS_V6= -IMGS_HTTP_V4=$IMGS_V4:80 -IMGS_HTTP_V6=[$IMGS_V6]:80 -IMGS_HTTPS_V4=$IMGS_V4:443 -IMGS_HTTPS_V6=[$IMGS_V6]:443 -IMGS_SSH_V4=$IMGS_V4:22 -IMGS_SSH_V6=[$IMGS_V6]:22 -IMGS_HOST= -IMGS_SSH_PORT=2222 -IMGS_WEB_PORT=3000 -IMGS_PROM_PORT=9222 -IMGS_DOMAIN=imgs.dev.pico.sh:3003 -IMGS_EMAIL=hello@pico.sh -IMGS_PROTOCOL=http -IMGS_STORAGE_DIR=.storage -IMGS_DEBUG=1 - SENDGRID_API_KEY= FEEDS_CADDYFILE=./caddy/Caddyfile FEEDS_V4= diff --git a/cmd/imgs/ssh/main.go b/cmd/imgs/ssh/main.go deleted file mode 100644 index 17c749b2..00000000 --- a/cmd/imgs/ssh/main.go +++ /dev/null @@ -1,9 +0,0 @@ -package main - -import ( - "github.com/picosh/pico/imgs" -) - -func main() { - imgs.StartSshServer() -} diff --git a/cmd/imgs/web/main.go b/cmd/imgs/web/main.go deleted file mode 100644 index b92a7db6..00000000 --- a/cmd/imgs/web/main.go +++ /dev/null @@ -1,7 +0,0 @@ -package main - -import "github.com/picosh/pico/imgs" - -func main() { - imgs.StartApiServer() -} diff --git a/docker-compose.override.yml b/docker-compose.override.yml index 4964ca4d..fa1a8397 100644 --- a/docker-compose.override.yml +++ b/docker-compose.override.yml @@ -11,13 +11,6 @@ services: ports: - "9000:9000" - "9001:9001" - registry: - env_file: - - .env.example - ports: - - "5000:5000" - volumes: - - ./imgs/registry.yml:/etc/docker/registry/config.yml imgproxy: env_file: - .env.example @@ -87,29 +80,6 @@ services: - ./data/prose-ssh/data:/app/ssh_data ports: - "2222:2222" - imgs-web: - build: - args: - APP: imgs - target: release-web - env_file: - - .env.example - volumes: - - ./data/storage/data:/app/.storage - ports: - - "3003:3000" - imgs-ssh: - build: - args: - APP: imgs - target: release-ssh - env_file: - - .env.example - volumes: - - ./data/storage/data:/app/.storage - - ./data/imgs-ssh/data:/app/ssh_data - ports: - - "2223:2222" pgs-web: build: args: diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml index 212c04d1..abe0f7f2 100644 --- a/docker-compose.prod.yml +++ b/docker-compose.prod.yml @@ -35,13 +35,6 @@ services: - .env.prod volumes: - ./data/pipemgr/data/term_info_ed25519:/key:ro - registry: - env_file: - - .env.prod - volumes: - - ./imgs/registry.yml:/etc/docker/registry/config.yml - networks: - - imgs imgproxy: env_file: - .env.prod @@ -186,53 +179,6 @@ services: ports: - "${PROSE_SSH_V4:-22}:2222" - "${PROSE_SSH_V6:-[::1]:22}:2222" - imgs-caddy: - image: ghcr.io/picosh/pico/caddy:latest - restart: always - networks: - - imgs - env_file: - - .env.prod - environment: - APP_DOMAIN: ${IMGS_DOMAIN:-imgs.sh} - APP_EMAIL: ${IMGS_EMAIL:-hello@pico.sh} - volumes: - - ${IMGS_CADDYFILE}:/etc/caddy/Caddyfile - - ./data/imgs-caddy/data:/data - - ./data/imgs-caddy/config:/config - ports: - - "${IMGS_HTTPS_V4:-443}:443" - - "${IMGS_HTTP_V4:-80}:80" - - "${IMGS_HTTPS_V6:-[::1]:443}:443" - - "${IMGS_HTTP_V6:-[::1]:80}:80" - profiles: - - imgs - - caddy - - all - imgs-web: - networks: - imgs: - aliases: - - web - env_file: - - .env.prod - volumes: - - ./data/storage/data:/app/.storage - - ./data/imgs-ssh/data:/app/ssh_data - imgs-ssh: - networks: - imgs: - aliases: - - ssh - env_file: - - .env.prod - volumes: - - ./data/storage/data:/app/.storage - - ./data/imgs-ssh/data:/app/ssh_data - - ./data/imgs-tmp:/tmp - ports: - - "${IMGS_SSH_V4:-22}:2222" - - "${IMGS_SSH_V6:-[::1]:22}:2222" pgs-caddy: image: ghcr.io/picosh/pico/caddy:latest restart: always @@ -392,12 +338,6 @@ networks: ipam: config: - subnet: 172.19.0.0/16 - imgs: - driver_opts: - com.docker.network.bridge.name: imgs - ipam: - config: - - subnet: 172.21.0.0/16 feeds: driver_opts: com.docker.network.bridge.name: feeds diff --git a/docker-compose.yml b/docker-compose.yml index 5f71bcca..5ae1370c 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -12,16 +12,6 @@ services: profiles: - db - all - registry: - image: registry - restart: always - profiles: - - imgs - - services - - all - environment: - REGISTRY_STORAGE_S3_ACCESSKEY: ${MINIO_ROOT_USER} - REGISTRY_STORAGE_S3_SECRETKEY: ${MINIO_ROOT_PASSWORD} imgproxy: image: darthsim/imgproxy:latest restart: always @@ -85,20 +75,6 @@ services: - prose - services - all - imgs-web: - image: ghcr.io/picosh/pico/imgs-web:latest - restart: always - profiles: - - imgs - - services - - all - imgs-ssh: - image: ghcr.io/picosh/pico/imgs-ssh:latest - restart: always - profiles: - - imgs - - services - - all pgs-web: image: ghcr.io/picosh/pico/pgs-web:latest restart: always diff --git a/imgs/api.go b/imgs/api.go index ee6d4bfa..0d1ab104 100644 --- a/imgs/api.go +++ b/imgs/api.go @@ -1,19 +1,13 @@ package imgs import ( - "bytes" "fmt" "html/template" "net/http" "net/url" "path/filepath" - "time" - _ "net/http/pprof" - - "github.com/gorilla/feeds" "github.com/picosh/pico/db" - "github.com/picosh/pico/db/postgres" "github.com/picosh/pico/pgs" "github.com/picosh/pico/shared" "github.com/picosh/pico/shared/storage" @@ -90,82 +84,6 @@ func ImgsListHandler(w http.ResponseWriter, r *http.Request) { } } -func ImgsRssHandler(w http.ResponseWriter, r *http.Request) { - dbpool := shared.GetDB(r) - logger := shared.GetLogger(r) - cfg := shared.GetCfg(r) - - pager, err := dbpool.FindAllPosts(&db.Pager{Num: 25, Page: 0}, Space) - if err != nil { - logger.Error(err.Error()) - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - - ts, err := template.ParseFiles(cfg.StaticPath("html/rss.page.tmpl")) - if err != nil { - logger.Error(err.Error()) - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - - feed := &feeds.Feed{ - Title: fmt.Sprintf("%s imgs feed", cfg.Domain), - Link: &feeds.Link{Href: cfg.HomeURL()}, - Description: fmt.Sprintf("%s latest image", cfg.Domain), - Author: &feeds.Author{Name: cfg.Domain}, - Created: time.Now(), - } - - curl := shared.CreateURLFromRequest(cfg, r) - - var feedItems []*feeds.Item - for _, post := range pager.Data { - var tpl bytes.Buffer - data := &PostPageData{ - ImgURL: template.URL(cfg.ImgURL(curl, post.Username, post.Filename)), - } - if err := ts.Execute(&tpl, data); err != nil { - continue - } - - realUrl := cfg.FullPostURL(curl, post.Username, post.Filename) - if !curl.Subdomain && !curl.UsernameInRoute { - realUrl = fmt.Sprintf("%s://%s%s", cfg.Protocol, r.Host, realUrl) - } - - item := &feeds.Item{ - Id: realUrl, - Title: post.Title, - Link: &feeds.Link{Href: realUrl}, - Content: tpl.String(), - Created: *post.PublishAt, - Updated: *post.UpdatedAt, - Description: post.Description, - Author: &feeds.Author{Name: post.Username}, - } - - if post.Description != "" { - item.Description = post.Description - } - - feedItems = append(feedItems, item) - } - feed.Items = feedItems - - rss, err := feed.ToAtom() - if err != nil { - logger.Error(err.Error()) - http.Error(w, "Could not generate atom rss feed", http.StatusInternalServerError) - } - - w.Header().Add("Content-Type", "application/atom+xml") - _, err = w.Write([]byte(rss)) - if err != nil { - logger.Error(err.Error()) - } -} - func anyPerm(proj *db.Project) bool { return true } @@ -248,102 +166,3 @@ func FindImgPost(r *http.Request, user *db.User, slug string) (*db.Post, error) dbpool := shared.GetDB(r) return dbpool.FindPostWithSlug(slug, user.ID, Space) } - -func redirectHandler(w http.ResponseWriter, r *http.Request) { - username := shared.GetUsernameFromRequest(r) - url := fmt.Sprintf("https://%s.prose.sh/i", username) - http.Redirect(w, r, url, http.StatusMovedPermanently) -} - -func createMainRoutes(staticRoutes []shared.Route) []shared.Route { - routes := []shared.Route{ - shared.NewRoute("GET", "/check", shared.CheckHandler), - shared.NewRoute("GET", "/", func(w http.ResponseWriter, r *http.Request) { - http.Redirect(w, r, "https://prose.sh", http.StatusMovedPermanently) - }), - } - - routes = append( - routes, - staticRoutes..., - ) - - routes = append( - routes, - shared.NewRoute("GET", "/rss", ImgsRssHandler), - shared.NewRoute("GET", "/rss.xml", ImgsRssHandler), - shared.NewRoute("GET", "/atom.xml", ImgsRssHandler), - shared.NewRoute("GET", "/feed.xml", ImgsRssHandler), - - shared.NewRoute("GET", "/([^/]+)", redirectHandler), - shared.NewRoute("GET", "/([^/]+)/o/([^/]+)", ImgRequest), - shared.NewRoute("GET", "/([^/]+)/([^/]+)", ImgRequest), - shared.NewRoute("GET", "/([^/]+)/([^/]+)/(.+)", ImgRequest), - ) - - return routes -} - -func createSubdomainRoutes(staticRoutes []shared.Route) []shared.Route { - routes := []shared.Route{} - - routes = append( - routes, - staticRoutes..., - ) - - routes = append( - routes, - shared.NewRoute("GET", "/", redirectHandler), - shared.NewRoute("GET", "/o/([^/]+)", ImgRequest), - shared.NewRoute("GET", "/([^/]+)", ImgRequest), - shared.NewRoute("GET", "/([^/]+)/(.+)", ImgRequest), - ) - - return routes -} - -func StartApiServer() { - cfg := NewConfigSite() - logger := cfg.Logger - - db := postgres.NewDB(cfg.DbURL, cfg.Logger) - defer db.Close() - - var st storage.StorageServe - var err error - if cfg.MinioURL == "" { - st, err = storage.NewStorageFS(cfg.Logger, cfg.StorageDir) - } else { - st, err = storage.NewStorageMinio(cfg.Logger, cfg.MinioURL, cfg.MinioUser, cfg.MinioPass) - } - - if err != nil { - logger.Error(err.Error()) - } - - staticRoutes := []shared.Route{} - if cfg.Debug { - staticRoutes = shared.CreatePProfRoutes(staticRoutes) - } - - mainRoutes := createMainRoutes(staticRoutes) - subdomainRoutes := createSubdomainRoutes(staticRoutes) - - apiConfig := &shared.ApiConfig{ - Cfg: cfg, - Dbpool: db, - Storage: st, - } - handler := shared.CreateServe(mainRoutes, subdomainRoutes, apiConfig) - router := http.HandlerFunc(handler) - - portStr := fmt.Sprintf(":%s", cfg.Port) - logger.Info( - "Starting server on port", - "port", cfg.Port, - "domain", cfg.Domain, - ) - - logger.Error(http.ListenAndServe(portStr, router).Error()) -} diff --git a/imgs/cli.go b/imgs/cli.go deleted file mode 100644 index 57529c8d..00000000 --- a/imgs/cli.go +++ /dev/null @@ -1,275 +0,0 @@ -package imgs - -import ( - "encoding/json" - "flag" - "fmt" - "io" - "log/slog" - "net/http" - "path/filepath" - "strings" - - "github.com/charmbracelet/ssh" - "github.com/charmbracelet/wish" - "github.com/google/uuid" - "github.com/picosh/pico/db" - "github.com/picosh/pico/shared/storage" - "github.com/picosh/pico/tui/common" - sst "github.com/picosh/pobj/storage" - psub "github.com/picosh/pubsub" - sendutils "github.com/picosh/send/utils" - "github.com/picosh/utils" -) - -func getUser(s ssh.Session, dbpool db.DB) (*db.User, error) { - if s.PublicKey() == nil { - return nil, fmt.Errorf("key not found") - } - - key := utils.KeyForKeyText(s.PublicKey()) - - user, err := dbpool.FindUserForKey(s.User(), key) - if err != nil { - return nil, err - } - - if user.Name == "" { - return nil, fmt.Errorf("must have username set") - } - - return user, nil -} - -func flagSet(cmdName string, sesh ssh.Session) (*flag.FlagSet, *bool) { - cmd := flag.NewFlagSet(cmdName, flag.ContinueOnError) - cmd.SetOutput(sesh) - write := cmd.Bool("write", false, "apply changes") - return cmd, write -} - -func flagCheck(cmd *flag.FlagSet, posArg string, cmdArgs []string) bool { - _ = cmd.Parse(cmdArgs) - - if posArg == "-h" || posArg == "--help" || posArg == "-help" { - cmd.Usage() - return false - } - return true -} - -type Cmd struct { - User *db.User - Session utils.CmdSession - Log *slog.Logger - Dbpool db.DB - Write bool - Styles common.Styles - Storage sst.ObjectStorage - RegistryUrl string -} - -func (c *Cmd) output(out string) { - _, _ = c.Session.Write([]byte(out + "\r\n")) -} - -func (c *Cmd) error(err error) { - _, _ = fmt.Fprint(c.Session.Stderr(), err, "\r\n") - _ = c.Session.Exit(1) - _ = c.Session.Close() -} - -func (c *Cmd) bail(err error) { - if err == nil { - return - } - c.Log.Error(err.Error()) - c.error(err) -} - -func (c *Cmd) notice() { - if !c.Write { - c.output("\nNOTICE: changes not commited, use `--write` to save operation") - } -} - -func (c *Cmd) help() { - helpStr := "Commands: [help, ls, rm]\n" - helpStr += "NOTICE: *must* append with `--write` for the changes to persist.\n" - c.output(helpStr) -} - -func (c *Cmd) rm(repo string) error { - bucket, err := c.Storage.GetBucket("imgs") - if err != nil { - return err - } - - fp := filepath.Join("docker/registry/v2/repositories", c.User.Name, repo) - - fileList, err := c.Storage.ListObjects(bucket, fp, true) - if err != nil { - return err - } - - if len(fileList) == 0 { - c.output(fmt.Sprintf("repo not found (%s)", repo)) - return nil - } - c.output(fmt.Sprintf("found (%d) objects for repo (%s), removing", len(fileList), repo)) - - for _, obj := range fileList { - fname := filepath.Join(fp, obj.Name()) - intent := fmt.Sprintf("deleted (%s)", obj.Name()) - c.Log.Info( - "attempting to delete file", - "user", c.User.Name, - "bucket", bucket.Name, - "repo", repo, - "filename", fname, - ) - if c.Write { - err := c.Storage.DeleteObject(bucket, fname) - if err != nil { - return err - } - } - c.output(intent) - } - - return nil -} - -type RegistryCatalog struct { - Repos []string `json:"repositories"` -} - -func (c *Cmd) ls() error { - res, err := http.Get( - fmt.Sprintf("http://%s/v2/_catalog", c.RegistryUrl), - ) - if err != nil { - return err - } - - body, err := io.ReadAll(res.Body) - if err != nil { - return err - } - - var data RegistryCatalog - err = json.Unmarshal(body, &data) - - if err != nil { - return err - } - - if len(data.Repos) == 0 { - c.output("You don't have any repos on imgs.sh") - return nil - } - - user := c.User.Name - out := "repos\n" - out += "-----\n" - for _, repo := range data.Repos { - if !strings.HasPrefix(repo, user+"/") { - continue - } - rr := strings.TrimPrefix(repo, user+"/") - out += fmt.Sprintf("%s\n", rr) - } - c.output(out) - return nil -} - -type CliHandler struct { - DBPool db.DB - Logger *slog.Logger - Storage storage.StorageServe - RegistryUrl string - PubSub psub.PubSub -} - -func WishMiddleware(handler *CliHandler) wish.Middleware { - dbpool := handler.DBPool - log := handler.Logger - st := handler.Storage - pubsub := handler.PubSub - - return func(next ssh.Handler) ssh.Handler { - return func(sesh ssh.Session) { - user, err := getUser(sesh, dbpool) - if err != nil { - sendutils.ErrorHandler(sesh, err) - return - } - - args := sesh.Command() - - opts := Cmd{ - Session: sesh, - User: user, - Log: log, - Dbpool: dbpool, - Write: false, - Storage: st, - RegistryUrl: handler.RegistryUrl, - } - - if len(args) == 0 { - next(sesh) - return - } - - cmd := strings.TrimSpace(args[0]) - if len(args) == 1 { - if cmd == "help" { - opts.help() - return - } else if cmd == "ls" { - err := opts.ls() - opts.bail(err) - return - } else { - next(sesh) - return - } - } - - repoName := strings.TrimSpace(args[1]) - cmdArgs := args[2:] - log.Info( - "imgs middleware detected command", - "args", args, - "cmd", cmd, - "repoName", repoName, - "cmdArgs", cmdArgs, - ) - - if cmd == "rm" { - rmCmd, write := flagSet("rm", sesh) - if !flagCheck(rmCmd, repoName, cmdArgs) { - return - } - opts.Write = *write - - err := opts.rm(repoName) - opts.notice() - opts.bail(err) - return - } else if cmd == "sub" { - err = pubsub.Sub(sesh.Context(), uuid.NewString(), sesh, []*psub.Channel{ - psub.NewChannel(fmt.Sprintf("%s/%s", user.Name, repoName)), - }, false) - - if err != nil { - wish.Errorln(sesh, err) - } - } else { - next(sesh) - return - } - } - } -} diff --git a/imgs/config.go b/imgs/config.go deleted file mode 100644 index e1af2889..00000000 --- a/imgs/config.go +++ /dev/null @@ -1,35 +0,0 @@ -package imgs - -import ( - "github.com/picosh/pico/shared" - "github.com/picosh/utils" -) - -func NewConfigSite() *shared.ConfigSite { - debug := utils.GetEnv("IMGS_DEBUG", "0") - domain := utils.GetEnv("IMGS_DOMAIN", "prose.sh") - port := utils.GetEnv("IMGS_WEB_PORT", "3000") - protocol := utils.GetEnv("IMGS_PROTOCOL", "https") - storageDir := utils.GetEnv("IMGS_STORAGE_DIR", ".storage") - minioURL := utils.GetEnv("MINIO_URL", "") - minioUser := utils.GetEnv("MINIO_ROOT_USER", "") - minioPass := utils.GetEnv("MINIO_ROOT_PASSWORD", "") - dbURL := utils.GetEnv("DATABASE_URL", "") - - cfg := shared.ConfigSite{ - Debug: debug == "1", - Domain: domain, - Port: port, - Protocol: protocol, - DbURL: dbURL, - StorageDir: storageDir, - MinioURL: minioURL, - MinioUser: minioUser, - MinioPass: minioPass, - Space: "imgs", - AllowedExt: []string{".jpg", ".jpeg", ".png", ".gif", ".webp", ".svg", ".ico"}, - Logger: shared.CreateLogger("imgs"), - } - - return &cfg -} diff --git a/imgs/registry.yml b/imgs/registry.yml deleted file mode 100644 index e364dcef..00000000 --- a/imgs/registry.yml +++ /dev/null @@ -1,11 +0,0 @@ -version: 0.1 -http: - addr: :5000 -storage: - s3: - region: us-east-1 - bucket: imgs - # regionendpoint: http://minio:9000 - regionendpoint: https://minio.pico.sh - redirect: - disable: true diff --git a/imgs/ssh.go b/imgs/ssh.go deleted file mode 100644 index 5c56313d..00000000 --- a/imgs/ssh.go +++ /dev/null @@ -1,318 +0,0 @@ -package imgs - -import ( - "bytes" - "context" - "encoding/json" - "fmt" - "io" - "log" - "log/slog" - "net/http" - "net/http/httputil" - "net/url" - "os" - "os/signal" - "strconv" - "strings" - "syscall" - "time" - - "github.com/charmbracelet/promwish" - "github.com/charmbracelet/ssh" - "github.com/charmbracelet/wish" - "github.com/google/uuid" - "github.com/picosh/pico/db" - "github.com/picosh/pico/db/postgres" - "github.com/picosh/pico/shared" - "github.com/picosh/pico/shared/storage" - wsh "github.com/picosh/pico/wish" - psub "github.com/picosh/pubsub" - "github.com/picosh/tunkit" - "github.com/picosh/utils" -) - -type ctxUserKey struct{} - -func getUserCtx(ctx ssh.Context) (*db.User, error) { - user, ok := ctx.Value(ctxUserKey{}).(*db.User) - if user == nil || !ok { - return user, fmt.Errorf("user not set on `ssh.Context()` for connection") - } - return user, nil -} -func setUserCtx(ctx ssh.Context, user *db.User) { - ctx.SetValue(ctxUserKey{}, user) -} - -func AuthHandler(dbh db.DB, log *slog.Logger) func(ssh.Context, ssh.PublicKey) bool { - return func(ctx ssh.Context, key ssh.PublicKey) bool { - kk := utils.KeyForKeyText(key) - - user, err := dbh.FindUserForKey("", kk) - if err != nil { - log.Error("user not found", "err", err) - return false - } - - if user == nil { - log.Error("user not found", "err", err) - return false - } - - setUserCtx(ctx, user) - - if !dbh.HasFeatureForUser(user.ID, "plus") { - log.Error("not a pico+ user", "user", user.Name) - return false - } - - return true - } -} - -type ErrorHandler struct { - Err error -} - -func (e *ErrorHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { - log.Println(e.Err.Error()) - http.Error(w, e.Err.Error(), http.StatusInternalServerError) -} - -func createServeMux(handler *CliHandler, pubsub psub.PubSub) func(ctx ssh.Context) http.Handler { - return func(ctx ssh.Context) http.Handler { - router := http.NewServeMux() - - slug := "" - user, err := getUserCtx(ctx) - if err == nil && user != nil { - slug = user.Name - } - - proxy := httputil.NewSingleHostReverseProxy(&url.URL{ - Scheme: "http", - Host: handler.RegistryUrl, - }) - - oldDirector := proxy.Director - - proxy.Director = func(r *http.Request) { - handler.Logger.Info("director", "request", r) - oldDirector(r) - - if strings.HasSuffix(r.URL.Path, "_catalog") || r.URL.Path == "/v2" || r.URL.Path == "/v2/" { - return - } - - fullPath := strings.TrimPrefix(r.URL.Path, "/v2") - - newPath, err := url.JoinPath("/v2", slug, fullPath) - if err != nil { - return - } - - r.URL.Path = newPath - - query := r.URL.Query() - - if query.Has("from") { - joinedFrom, err := url.JoinPath(slug, query.Get("from")) - if err != nil { - return - } - query.Set("from", joinedFrom) - - r.URL.RawQuery = query.Encode() - } - } - - proxy.ModifyResponse = func(r *http.Response) error { - handler.Logger.Info("modify", "request", r) - shared.CorsHeaders(r.Header) - - if r.Request.Method == http.MethodGet && strings.HasSuffix(r.Request.URL.Path, "_catalog") { - b, err := io.ReadAll(r.Body) - if err != nil { - return err - } - - err = r.Body.Close() - if err != nil { - return err - } - - var data map[string]any - err = json.Unmarshal(b, &data) - if err != nil { - return err - } - - newRepos := []string{} - - if repos, ok := data["repositories"].([]any); ok { - for _, repo := range repos { - if repoStr, ok := repo.(string); ok && strings.HasPrefix(repoStr, slug) { - newRepos = append(newRepos, strings.Replace(repoStr, fmt.Sprintf("%s/", slug), "", 1)) - } - } - } - - data["repositories"] = newRepos - - newB, err := json.Marshal(data) - if err != nil { - return err - } - - jsonBuf := bytes.NewBuffer(newB) - - r.ContentLength = int64(jsonBuf.Len()) - r.Header.Set("Content-Length", strconv.FormatInt(r.ContentLength, 10)) - r.Body = io.NopCloser(jsonBuf) - } - - if r.Request.Method == http.MethodGet && (strings.Contains(r.Request.URL.Path, "/tags/") || strings.Contains(r.Request.URL.Path, "/manifests/")) { - splitPath := strings.Split(r.Request.URL.Path, "/") - - if len(splitPath) > 1 { - ele := splitPath[len(splitPath)-2] - if ele == "tags" || ele == "manifests" { - b, err := io.ReadAll(r.Body) - if err != nil { - return err - } - - err = r.Body.Close() - if err != nil { - return err - } - - var data map[string]any - err = json.Unmarshal(b, &data) - if err != nil { - return err - } - - if name, ok := data["name"].(string); ok { - if strings.HasPrefix(name, slug) { - data["name"] = strings.Replace(name, fmt.Sprintf("%s/", slug), "", 1) - } - } - - newB, err := json.Marshal(data) - if err != nil { - return err - } - - jsonBuf := bytes.NewBuffer(newB) - - r.ContentLength = int64(jsonBuf.Len()) - r.Header.Set("Content-Length", strconv.FormatInt(r.ContentLength, 10)) - r.Body = io.NopCloser(jsonBuf) - } - } - } - - if r.Request.Method == http.MethodPut && strings.Contains(r.Request.URL.Path, "/manifests/") { - digest := r.Header.Get("Docker-Content-Digest") - // [ ]/v2/erock/alpine/manifests/latest - splitPath := strings.Split(r.Request.URL.Path, "/") - img := splitPath[3] - tag := splitPath[5] - - furl := fmt.Sprintf( - "digest=%s&image=%s&tag=%s", - url.QueryEscape(digest), - img, - tag, - ) - handler.Logger.Info("sending event", "url", furl) - - err := pubsub.Pub(ctx, uuid.NewString(), bytes.NewBufferString(furl), []*psub.Channel{ - psub.NewChannel(fmt.Sprintf("%s/%s:%s", user.Name, img, tag)), - }, false) - - if err != nil { - handler.Logger.Error("pub error", "err", err) - } - } - - locationHeader := r.Header.Get("location") - if strings.Contains(locationHeader, fmt.Sprintf("/v2/%s", slug)) { - r.Header.Set("location", strings.ReplaceAll(locationHeader, fmt.Sprintf("/v2/%s", slug), "/v2")) - } - - return nil - } - - router.HandleFunc("/", proxy.ServeHTTP) - - return router - } -} - -func StartSshServer() { - host := utils.GetEnv("IMGS_HOST", "0.0.0.0") - port := utils.GetEnv("IMGS_SSH_PORT", "2222") - promPort := utils.GetEnv("IMGS_PROM_PORT", "9222") - dbUrl := os.Getenv("DATABASE_URL") - registryUrl := utils.GetEnv("REGISTRY_URL", "0.0.0.0:5000") - minioUrl := utils.GetEnv("MINIO_URL", "http://0.0.0.0:9000") - minioUser := utils.GetEnv("MINIO_ROOT_USER", "") - minioPass := utils.GetEnv("MINIO_ROOT_PASSWORD", "") - - logger := shared.CreateLogger("imgs") - logger.Info("bootup", "registry", registryUrl, "minio", minioUrl) - dbh := postgres.NewDB(dbUrl, logger) - st, err := storage.NewStorageMinio(logger, minioUrl, minioUser, minioPass) - if err != nil { - panic(err) - } - - pubsub := psub.NewMulticast(logger) - handler := &CliHandler{ - Logger: logger, - DBPool: dbh, - Storage: st, - RegistryUrl: registryUrl, - PubSub: pubsub, - } - - s, err := wish.NewServer( - wish.WithAddress(fmt.Sprintf("%s:%s", host, port)), - wish.WithHostKeyPath("ssh_data/term_info_ed25519"), - wish.WithPublicKeyAuth(AuthHandler(dbh, logger)), - wish.WithMiddleware( - WishMiddleware(handler), - promwish.Middleware(fmt.Sprintf("%s:%s", host, promPort), "imgs-ssh"), - wsh.LogMiddleware(logger), - ), - tunkit.WithWebTunnel( - tunkit.NewWebTunnelHandler(createServeMux(handler, pubsub), logger), - ), - ) - - if err != nil { - logger.Error("could not create server", "err", err) - } - - done := make(chan os.Signal, 1) - signal.Notify(done, os.Interrupt, syscall.SIGINT, syscall.SIGTERM) - logger.Info("starting SSH server", "host", host, "port", port) - go func() { - if err = s.ListenAndServe(); err != nil { - logger.Error("serve error", "err", err) - os.Exit(1) - } - }() - - <-done - logger.Info("stopping SSH server") - ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) - defer func() { cancel() }() - if err := s.Shutdown(ctx); err != nil { - logger.Error("shutdown", "err", err) - os.Exit(1) - } -}