From 24a64fc36f7aa637e3c968f46a45cf3ca285e543 Mon Sep 17 00:00:00 2001 From: blacktop Date: Mon, 15 Jul 2024 20:12:37 -0600 Subject: [PATCH] fix: thread config.yml `daemon` `pem-db` config through `ipsw` API routes that can use it --- api/server/routes/ipsw/ipsw.go | 264 +++++++++++++++++-------------- api/server/routes/ipsw/routes.go | 8 +- api/server/routes/mount/mount.go | 6 +- api/server/routes/routes.go | 6 +- api/server/routes/syms/syms.go | 6 +- api/server/server.go | 4 +- 6 files changed, 160 insertions(+), 134 deletions(-) diff --git a/api/server/routes/ipsw/ipsw.go b/api/server/routes/ipsw/ipsw.go index 678f90953b..74d8b77114 100644 --- a/api/server/routes/ipsw/ipsw.go +++ b/api/server/routes/ipsw/ipsw.go @@ -40,99 +40,105 @@ type getFsFilesResponse struct { Files []File `json:"files"` } -func getFsFiles(c *gin.Context) { - ipswPath, ok := c.GetQuery("path") - if !ok { - c.AbortWithStatusJSON(http.StatusBadRequest, types.GenericError{Error: "missing path query parameter"}) - return - } else { - ipswPath = filepath.Clean(ipswPath) - } - pemDbPath, ok := c.GetQuery("pem_db") - if ok { - pemDbPath = filepath.Clean(pemDbPath) - } - - i, err := info.Parse(ipswPath) - if err != nil { - c.AbortWithStatusJSON(http.StatusInternalServerError, types.GenericError{Error: err.Error()}) - return - } - dmgPath, err := i.GetFileSystemOsDmg() - if err != nil { - c.AbortWithStatusJSON(http.StatusInternalServerError, types.GenericError{Error: err.Error()}) - return - } - if _, err := os.Stat(dmgPath); os.IsNotExist(err) { - // extract filesystem DMG - dmgs, err := utils.Unzip(ipswPath, "", func(f *zip.File) bool { - return strings.EqualFold(filepath.Base(f.Name), dmgPath) - }) - if err != nil { - c.AbortWithStatusJSON(http.StatusInternalServerError, types.GenericError{Error: fmt.Sprintf("failed to extract %s from IPSW: %v", dmgPath, err)}) +func getFsFiles(pemDB string) gin.HandlerFunc { + return func(c *gin.Context) { + ipswPath, ok := c.GetQuery("path") + if !ok { + c.AbortWithStatusJSON(http.StatusBadRequest, types.GenericError{Error: "missing path query parameter"}) + return + } else { + ipswPath = filepath.Clean(ipswPath) } - if len(dmgs) == 0 { - c.AbortWithStatusJSON(http.StatusInternalServerError, types.GenericError{Error: fmt.Sprintf("failed to find %s in IPSW", dmgPath)}) + pemDbPath, ok := c.GetQuery("pem_db") + if ok { + pemDbPath = filepath.Clean(pemDbPath) + } else { + if pemDB != "" { + pemDbPath = filepath.Clean(pemDB) + } } - defer os.Remove(filepath.Clean(dmgs[0])) - } else { - utils.Indent(log.Debug, 2)(fmt.Sprintf("Found extracted %s", dmgPath)) - } - if filepath.Ext(dmgPath) == ".aea" { - dmgPath, err = aea.Decrypt(dmgPath, filepath.Dir(dmgPath), nil, pemDbPath) + i, err := info.Parse(ipswPath) if err != nil { - c.AbortWithStatusJSON(http.StatusInternalServerError, types.GenericError{Error: fmt.Sprintf("failed to parse AEA encrypted DMG: %v", err)}) + c.AbortWithStatusJSON(http.StatusInternalServerError, types.GenericError{Error: err.Error()}) + return } - } - - // mount filesystem DMG - utils.Indent(log.Info, 2)(fmt.Sprintf("Mounting %s", dmgPath)) - mountPoint, alreadyMounted, err := utils.MountDMG(dmgPath) - if err != nil { - if !errors.Is(err, utils.ErrMountResourceBusy) { - c.AbortWithStatusJSON(http.StatusInternalServerError, types.GenericError{Error: fmt.Sprintf("failed to mount DMG: %v", err)}) + dmgPath, err := i.GetFileSystemOsDmg() + if err != nil { + c.AbortWithStatusJSON(http.StatusInternalServerError, types.GenericError{Error: err.Error()}) + return } - } - if alreadyMounted { - utils.Indent(log.Info, 3)(fmt.Sprintf("%s already mounted", dmgPath)) - } else { - defer func() { - utils.Indent(log.Info, 2)(fmt.Sprintf("Unmounting %s", dmgPath)) - if err := utils.Retry(3, 2*time.Second, func() error { - return utils.Unmount(mountPoint, false) - }); err != nil { - log.Errorf("failed to unmount %s at %s: %v", dmgPath, mountPoint, err) + if _, err := os.Stat(dmgPath); os.IsNotExist(err) { + // extract filesystem DMG + dmgs, err := utils.Unzip(ipswPath, "", func(f *zip.File) bool { + return strings.EqualFold(filepath.Base(f.Name), dmgPath) + }) + if err != nil { + c.AbortWithStatusJSON(http.StatusInternalServerError, types.GenericError{Error: fmt.Sprintf("failed to extract %s from IPSW: %v", dmgPath, err)}) } - }() - } + if len(dmgs) == 0 { + c.AbortWithStatusJSON(http.StatusInternalServerError, types.GenericError{Error: fmt.Sprintf("failed to find %s in IPSW", dmgPath)}) + } + defer os.Remove(filepath.Clean(dmgs[0])) + } else { + utils.Indent(log.Debug, 2)(fmt.Sprintf("Found extracted %s", dmgPath)) + } + + if filepath.Ext(dmgPath) == ".aea" { + dmgPath, err = aea.Decrypt(dmgPath, filepath.Dir(dmgPath), nil, pemDbPath) + if err != nil { + c.AbortWithStatusJSON(http.StatusInternalServerError, types.GenericError{Error: fmt.Sprintf("failed to parse AEA encrypted DMG: %v", err)}) + } + } - var files []File - if err := filepath.Walk(mountPoint, func(path string, info fs.FileInfo, err error) error { + // mount filesystem DMG + utils.Indent(log.Info, 2)(fmt.Sprintf("Mounting %s", dmgPath)) + mountPoint, alreadyMounted, err := utils.MountDMG(dmgPath) if err != nil { - return fmt.Errorf("prevent panic by handling failure accessing a path %q: %v", path, err) + if !errors.Is(err, utils.ErrMountResourceBusy) { + c.AbortWithStatusJSON(http.StatusInternalServerError, types.GenericError{Error: fmt.Sprintf("failed to mount DMG: %v", err)}) + } + } + if alreadyMounted { + utils.Indent(log.Info, 3)(fmt.Sprintf("%s already mounted", dmgPath)) + } else { + defer func() { + utils.Indent(log.Info, 2)(fmt.Sprintf("Unmounting %s", dmgPath)) + if err := utils.Retry(3, 2*time.Second, func() error { + return utils.Unmount(mountPoint, false) + }); err != nil { + log.Errorf("failed to unmount %s at %s: %v", dmgPath, mountPoint, err) + } + }() } - if info.IsDir() { + + var files []File + if err := filepath.Walk(mountPoint, func(path string, info fs.FileInfo, err error) error { + if err != nil { + return fmt.Errorf("prevent panic by handling failure accessing a path %q: %v", path, err) + } + if info.IsDir() { + return nil + // return filepath.SkipDir + } + fpath, err := filepath.Rel(mountPoint, path) + if err != nil { + return fmt.Errorf("failed to get relative path for %s: %v", path, err) + } + files = append(files, File{ + Name: fpath, + Size: info.Size(), + Mode: info.Mode().String(), + ModTime: info.ModTime(), + }) return nil - // return filepath.SkipDir + }); err != nil { + c.AbortWithStatusJSON(http.StatusInternalServerError, types.GenericError{Error: err.Error()}) + return } - fpath, err := filepath.Rel(mountPoint, path) - if err != nil { - return fmt.Errorf("failed to get relative path for %s: %v", path, err) - } - files = append(files, File{ - Name: fpath, - Size: info.Size(), - Mode: info.Mode().String(), - ModTime: info.ModTime(), - }) - return nil - }); err != nil { - c.AbortWithStatusJSON(http.StatusInternalServerError, types.GenericError{Error: err.Error()}) - return - } - c.IndentedJSON(http.StatusOK, getFsFilesResponse{Path: ipswPath, Files: files}) + c.IndentedJSON(http.StatusOK, getFsFilesResponse{Path: ipswPath, Files: files}) + } } // swagger:response @@ -141,36 +147,42 @@ type getFsEntitlementsResponse struct { Entitlements map[string]map[string]any `json:"entitlements"` } -func getFsEntitlements(c *gin.Context) { - ipswPath, ok := c.GetQuery("path") - if !ok { - c.AbortWithStatusJSON(http.StatusBadRequest, types.GenericError{Error: "missing path query parameter"}) - return - } else { - ipswPath = filepath.Clean(ipswPath) - } - pemDbPath, ok := c.GetQuery("pem_db") - if ok { - pemDbPath = filepath.Clean(pemDbPath) - } +func getFsEntitlements(pemDB string) gin.HandlerFunc { + return func(c *gin.Context) { + ipswPath, ok := c.GetQuery("path") + if !ok { + c.AbortWithStatusJSON(http.StatusBadRequest, types.GenericError{Error: "missing path query parameter"}) + return + } else { + ipswPath = filepath.Clean(ipswPath) + } + pemDbPath, ok := c.GetQuery("pem_db") + if ok { + pemDbPath = filepath.Clean(pemDbPath) + } else { + if pemDB != "" { + pemDbPath = filepath.Clean(pemDB) + } + } - ents, err := ent.GetDatabase(&ent.Config{IPSW: ipswPath, PemDB: pemDbPath}) - if err != nil { - c.AbortWithStatusJSON(http.StatusInternalServerError, types.GenericError{Error: err.Error()}) - return - } + ents, err := ent.GetDatabase(&ent.Config{IPSW: ipswPath, PemDB: pemDbPath}) + if err != nil { + c.AbortWithStatusJSON(http.StatusInternalServerError, types.GenericError{Error: err.Error()}) + return + } - entDB := make(map[string]map[string]any) + entDB := make(map[string]map[string]any) - for f, ent := range ents { - ents := make(map[string]any) - if err := plist.NewDecoder(bytes.NewReader([]byte(ent))).Decode(&ents); err != nil { - c.AbortWithStatusJSON(http.StatusInternalServerError, types.GenericError{Error: fmt.Sprintf("failed to decode entitlements plist for %s: %v", f, err)}) + for f, ent := range ents { + ents := make(map[string]any) + if err := plist.NewDecoder(bytes.NewReader([]byte(ent))).Decode(&ents); err != nil { + c.AbortWithStatusJSON(http.StatusInternalServerError, types.GenericError{Error: fmt.Sprintf("failed to decode entitlements plist for %s: %v", f, err)}) + } + entDB[f] = ents } - entDB[f] = ents - } - c.IndentedJSON(http.StatusOK, getFsEntitlementsResponse{Path: ipswPath, Entitlements: entDB}) + c.IndentedJSON(http.StatusOK, getFsEntitlementsResponse{Path: ipswPath, Entitlements: entDB}) + } } // swagger:response @@ -179,24 +191,30 @@ type getFsLaunchdConfigResponse struct { LaunchdConfig string `json:"launchd_config"` } -func getFsLaunchdConfig(c *gin.Context) { - ipswPath, ok := c.GetQuery("path") - if !ok { - c.AbortWithStatusJSON(http.StatusBadRequest, types.GenericError{Error: "missing path query parameter"}) - return - } else { - ipswPath = filepath.Clean(ipswPath) - } - pemDbPath, ok := c.GetQuery("pem_db") - if ok { - pemDbPath = filepath.Clean(pemDbPath) - } +func getFsLaunchdConfig(pemDB string) gin.HandlerFunc { + return func(c *gin.Context) { + ipswPath, ok := c.GetQuery("path") + if !ok { + c.AbortWithStatusJSON(http.StatusBadRequest, types.GenericError{Error: "missing path query parameter"}) + return + } else { + ipswPath = filepath.Clean(ipswPath) + } + pemDbPath, ok := c.GetQuery("pem_db") + if ok { + pemDbPath = filepath.Clean(pemDbPath) + } else { + if pemDB != "" { + pemDbPath = filepath.Clean(pemDB) + } + } - ldconf, err := extract.LaunchdConfig(ipswPath, pemDbPath) - if err != nil { - c.AbortWithStatusJSON(http.StatusInternalServerError, types.GenericError{Error: err.Error()}) - return - } + ldconf, err := extract.LaunchdConfig(ipswPath, pemDbPath) + if err != nil { + c.AbortWithStatusJSON(http.StatusInternalServerError, types.GenericError{Error: err.Error()}) + return + } - c.IndentedJSON(http.StatusOK, getFsLaunchdConfigResponse{Path: ipswPath, LaunchdConfig: ldconf}) + c.IndentedJSON(http.StatusOK, getFsLaunchdConfigResponse{Path: ipswPath, LaunchdConfig: ldconf}) + } } diff --git a/api/server/routes/ipsw/routes.go b/api/server/routes/ipsw/routes.go index 3edda2e32c..42c2c9bab1 100644 --- a/api/server/routes/ipsw/routes.go +++ b/api/server/routes/ipsw/routes.go @@ -5,7 +5,7 @@ import ( ) // AddRoutes adds the download routes to the router -func AddRoutes(rg *gin.RouterGroup) { +func AddRoutes(rg *gin.RouterGroup, pemDB string) { dl := rg.Group("/ipsw") // swagger:route GET /ipsw/fs/files IPSW getIpswFsFiles // @@ -31,7 +31,7 @@ func AddRoutes(rg *gin.RouterGroup) { // Responses: // 200: getFsFilesResponse // 500: genericError - dl.GET("/fs/files", getFsFiles) + dl.GET("/fs/files", getFsFiles(pemDB)) // swagger:route GET /ipsw/fs/ents IPSW getIpswFsEntitlements // // Entitlements @@ -56,7 +56,7 @@ func AddRoutes(rg *gin.RouterGroup) { // Responses: // 200: getFsEntitlementsResponse // 500: genericError - dl.GET("/fs/ents", getFsEntitlements) + dl.GET("/fs/ents", getFsEntitlements(pemDB)) // swagger:route GET /ipsw/fs/launchd IPSW getIpswFsLaunchd // // launchd Config @@ -81,5 +81,5 @@ func AddRoutes(rg *gin.RouterGroup) { // Responses: // 200: getFsLaunchdConfigResponse // 500: genericError - dl.GET("/fs/launchd", getFsLaunchdConfig) + dl.GET("/fs/launchd", getFsLaunchdConfig(pemDB)) } diff --git a/api/server/routes/mount/mount.go b/api/server/routes/mount/mount.go index 5d7fe14e39..7d5fe0f5d9 100644 --- a/api/server/routes/mount/mount.go +++ b/api/server/routes/mount/mount.go @@ -24,7 +24,7 @@ type successResponse struct { } // AddRoutes adds the download routes to the router -func AddRoutes(rg *gin.RouterGroup) { +func AddRoutes(rg *gin.RouterGroup, pemDB string) { // swagger:route POST /mount/{type} Mount postMount // // Mount @@ -64,6 +64,10 @@ func AddRoutes(rg *gin.RouterGroup) { pemDbPath, ok := c.GetQuery("pem_db") if ok { pemDbPath = filepath.Clean(pemDbPath) + } else { + if pemDB != "" { + pemDbPath = filepath.Clean(pemDB) + } } dmgType := c.Param("type") if !utils.StrSliceContains([]string{"app", "sys", "fs"}, dmgType) { diff --git a/api/server/routes/routes.go b/api/server/routes/routes.go index 8abd3dc9fd..89d74f3fc1 100644 --- a/api/server/routes/routes.go +++ b/api/server/routes/routes.go @@ -18,7 +18,7 @@ import ( ) // Add adds the command routes to the router -func Add(rg *gin.RouterGroup) { +func Add(rg *gin.RouterGroup, pemDB string) { daemon.AddRoutes(rg) devicelist.AddRoutes(rg) diff.AddRoutes(rg) @@ -29,11 +29,11 @@ func Add(rg *gin.RouterGroup) { idev.AddRoutes(rg) // img4.AddRoutes(rg) // TODO: add img4 routes info.AddRoutes(rg) - ipsw.AddRoutes(rg) + ipsw.AddRoutes(rg, pemDB) kernel.AddRoutes(rg) macho.AddRoutes(rg) // mdevs.AddRoutes(rg) // TODO: add mdevs routes - mount.AddRoutes(rg) + mount.AddRoutes(rg, pemDB) // ota.AddRoutes(rg) // TODO: add ota routes // pongo.AddRoutes(rg) // TODO: add pongo routes // sepfw.AddRoutes(rg) // TODO: add sepfw routes diff --git a/api/server/routes/syms/syms.go b/api/server/routes/syms/syms.go index 8ef9b89cd0..61d81b6236 100644 --- a/api/server/routes/syms/syms.go +++ b/api/server/routes/syms/syms.go @@ -41,7 +41,7 @@ type IpswParams struct { } // AddRoutes adds the syms routes to the router -func AddRoutes(rg *gin.RouterGroup, db db.Database) { +func AddRoutes(rg *gin.RouterGroup, db db.Database, pemDB string) { // swagger:route POST /syms/scan Syms postScan // // Scan @@ -76,6 +76,10 @@ func AddRoutes(rg *gin.RouterGroup, db db.Database) { pemDbPath, ok := c.GetQuery("pem_db") if ok { pemDbPath = filepath.Clean(pemDbPath) + } else { + if pemDB != "" { + pemDbPath = filepath.Clean(pemDB) + } } if err := syms.Scan(ipswPath, pemDbPath, db); err != nil { c.AbortWithStatusJSON(http.StatusInternalServerError, types.GenericError{Error: err.Error()}) diff --git a/api/server/server.go b/api/server/server.go index a001be6a1f..b797f49ce1 100644 --- a/api/server/server.go +++ b/api/server/server.go @@ -93,10 +93,10 @@ func (s *Server) Start(db db.Database) error { rg := s.router.Group("/v" + api.DefaultVersion) - routes.Add(rg) + routes.Add(rg, s.conf.PemDB) if db != nil { - syms.AddRoutes(rg, db) + syms.AddRoutes(rg, db, s.conf.PemDB) } if s.conf.PemDB != "" {