Skip to content

Commit

Permalink
Remove Perms section from, AppImage, slight refactor
Browse files Browse the repository at this point in the history
 * Remove `Run` method in favor of running the AppImage directly,
   outside of aisap
 * Remove `AppImage.Perms` from AppImage
 * Removed old `profilegen` app
  • Loading branch information
mgord9518 committed Jul 1, 2024
1 parent a248850 commit 490ab39
Show file tree
Hide file tree
Showing 17 changed files with 517 additions and 446 deletions.
167 changes: 103 additions & 64 deletions appimage.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,43 +8,42 @@ import (
"bufio"
"crypto/md5"
"debug/elf"
"fmt"
"errors"
"fmt"
"io"
"os"
"path"
"path/filepath"
"os"
"strings"

ini "gopkg.in/ini.v1"
helpers "github.com/mgord9518/aisap/helpers"
profiles "github.com/mgord9518/aisap/profiles"
squashfs "github.com/CalebQ42/squashfs"
xdg "github.com/adrg/xdg"
helpers "github.com/mgord9518/aisap/helpers"
permissions "github.com/mgord9518/aisap/permissions"
squashfs "github.com/CalebQ42/squashfs"
xdg "github.com/adrg/xdg"
profiles "github.com/mgord9518/aisap/profiles"
ini "gopkg.in/ini.v1"
)

type AppImage struct {
Desktop *ini.File // INI of internal desktop entry
Perms *permissions.AppImagePerms // Permissions
Path string // Location of AppImage
dataDir string // The AppImage's `HOME` directory
rootDir string // Can be used to give the AppImage fake system files
tempDir string // The AppImage's `/tmp` directory
mountDir string // The location the AppImage is mounted at
md5 string // MD5 of AppImage's URI
Name string // AppImage name from the desktop entry
Version string
UpdateInfo string
Offset int // Offset of SquashFS image
imageType int // Type of AppImage (1=ISO 9660 ELF, 2=squashfs ELF, -2=shImg shell)
Desktop *ini.File // INI of internal desktop entry
Path string // Location of AppImage
dataDir string // The AppImage's `HOME` directory
rootDir string // Can be used to give the AppImage fake system files
tempDir string // The AppImage's `/tmp` directory
mountDir string // The location the AppImage is mounted at
md5 string // MD5 of AppImage's URI
Name string // AppImage name from the desktop entry
Version string
UpdateInfo string
Offset int // Offset of SquashFS image
imageType int // Type of AppImage (1=ISO 9660 ELF, 2=squashfs ELF, -2=shImg shell)
architecture []string // List of CPU architectures supported by the bundle
reader *squashfs.Reader
file *os.File
reader *squashfs.Reader
file *os.File

// These will both be removed when the Zig-implemented C bindings
// become usable
CurrentArg int // Should only ever be used for the C bindings
CurrentArg int // Should only ever be used for the C bindings
WrapArgsList []string // Should only ever be used for the C bindings
}

Expand All @@ -69,35 +68,47 @@ func NewAppImage(src string) (*AppImage, error) {
ai.md5 = fmt.Sprintf("%x", b)

ai.imageType, err = helpers.GetAppImageType(ai.Path)
if err != nil { return nil, err }
if err != nil {
return nil, err
}

ai.rootDir = "/"
ai.dataDir = ai.Path + ".home"
ai.Offset, err = helpers.GetOffset(src)
if err != nil { return nil, err }
if err != nil {
return nil, err
}

if ai.imageType == -2 || ai.imageType == 2 {
ai.file, err = os.Open(ai.Path)
if err != nil { return nil, err }
if err != nil {
return nil, err
}

info, _ := ai.file.Stat()
off64 := int64(ai.Offset)
r := io.NewSectionReader(ai.file, off64, info.Size()-off64)

ai.reader, err = squashfs.NewReader(r)
if err != nil { return nil, err }
if err != nil {
return nil, err
}
}

// Prefer local entry if it exists (located at $XDG_DATA_HOME/aisap/[ai.Name])
desktopReader, err := ai.getEntry()
if err != nil { return ai, err }
if err != nil {
return ai, err
}

ai.Desktop, err = ini.LoadSources(ini.LoadOptions{
IgnoreInlineComment: true,
}, desktopReader)
if err != nil { return ai, err }
if err != nil {
return ai, err
}

ai.Name = ai.Desktop.Section("Desktop Entry").Key("Name").Value()
ai.Name = ai.Desktop.Section("Desktop Entry").Key("Name").Value()
ai.Version = ai.Desktop.Section("Desktop Entry").Key("X-AppImage-Version").Value()

ai.UpdateInfo, _ = helpers.ReadUpdateInfo(ai.Path)
Expand All @@ -106,6 +117,17 @@ func NewAppImage(src string) (*AppImage, error) {
ai.Version = "1.0"
}

return ai, nil
}

// Retrieve permissions from the AppImage in the following order:
//
// 1: User-configured settings in ~/.local/share/aisap/profiles/[ai.Name]
// 2: aisap internal permissions library
// 3: Permissions defined in the AppImage's desktop file
func (ai AppImage) Permissions() (*permissions.AppImagePerms, error) {
var perms *permissions.AppImagePerms
var err error

// If PREFER_AISAP_PROFILE is set, attempt to use it over the AppImage's
// suggested permissions. If no profile exists in aisap, fall back on saved
Expand All @@ -114,23 +136,25 @@ func NewAppImage(src string) (*AppImage, error) {
// Typically this should be unset unless testing a custom profile against
// aisap's
if _, present := os.LookupEnv("PREFER_AISAP_PROFILE"); present {
ai.Perms, err = profiles.FromName(ai.Name)
perms, err = profiles.FromName(ai.Name)

if err != nil {
ai.Perms, err = permissions.FromSystem(ai.Name)
perms, err = permissions.FromSystem(ai.Name)
}
} else {
ai.Perms, err = permissions.FromSystem(ai.Name)
perms, err = permissions.FromSystem(ai.Name)

if err != nil {
ai.Perms, err = profiles.FromName(ai.Name)
perms, err = profiles.FromName(ai.Name)
}
}

// Fall back to permissions inside AppImage if all else fails
if err != nil {
ai.Perms, _ = permissions.FromIni(ai.Desktop)
return permissions.FromIni(ai.Desktop)
}

return ai, nil
return perms, nil
}

// Returns `true` if the AppImage in question is both executable and has
Expand All @@ -149,7 +173,7 @@ func (ai *AppImage) Trusted() bool {
return false
}

return info.Mode() & 0100 != 0
return info.Mode()&0100 != 0
}

return false
Expand All @@ -169,7 +193,7 @@ func (ai *AppImage) SetTrusted(trusted bool) error {
return err
}

os.Chmod(ai.Path, info.Mode() | 0100)
os.Chmod(ai.Path, info.Mode()|0100)

if helpers.FileExists(filePath) {
return errors.New("entry already exists in aisap config dir")
Expand All @@ -190,7 +214,9 @@ func (ai *AppImage) Thumbnail() (io.Reader, error) {
// Try to extract from zip, continue to SquashFS if it fails
if ai.imageType == -2 {
r, err := helpers.ExtractResourceReader(ai.Path, "icon/256.png")
if err == nil { return r, nil }
if err == nil {
return r, nil
}
}

return ai.ExtractFileReader(".DirIcon")
Expand Down Expand Up @@ -252,26 +278,34 @@ func (ai *AppImage) ExtractFile(path string, dest string, resolveSymlinks bool)

// True if file is symlink and `resolveSymlinks` is false
if info != nil && !resolveSymlinks &&
info.Mode()&os.ModeSymlink == os.ModeSymlink {
info.Mode()&os.ModeSymlink == os.ModeSymlink {
target, _ := os.Readlink(path)
err = os.Symlink(target, dest)
} else {
inF, err := ai.ExtractFileReader(path)
defer inF.Close()
if err != nil { return err }
if err != nil {
return err
}

info, err := os.Stat(path)
perms := info.Mode().Perm()

outF, err := os.Create(dest)
defer outF.Close()
if err != nil { return err }
if err != nil {
return err
}

err = os.Chmod(dest, perms)
if err != nil { return err }
if err != nil {
return err
}

_, err = io.Copy(outF, inF)
if err != nil { return err }
if err != nil {
return err
}
}

return err
Expand All @@ -297,10 +331,14 @@ func (ai *AppImage) ExtractFileReader(path string) (io.ReadCloser, error) {
func (ai *AppImage) Icon() (io.ReadCloser, string, error) {
if ai.imageType == -2 {
r, err := helpers.ExtractResourceReader(ai.Path, "icon/default.svg")
if err == nil { return r, "icon/default.svg", nil }
if err == nil {
return r, "icon/default.svg", nil
}

r, err = helpers.ExtractResourceReader(ai.Path, "icon/default.png")
if err == nil { return r, "icon/default.png", nil }
r, err = helpers.ExtractResourceReader(ai.Path, "icon/default.png")
if err == nil {
return r, "icon/default.png", nil
}
}

if ai.Desktop == nil {
Expand All @@ -325,7 +363,7 @@ func (ai *AppImage) Icon() (io.ReadCloser, string, error) {
".svg",
}

for _, ext := range(extensions) {
for _, ext := range extensions {
r, err := ai.ExtractFileReader(iconf + ext)

if err == nil {
Expand All @@ -338,7 +376,7 @@ func (ai *AppImage) Icon() (io.ReadCloser, string, error) {

// Extract the desktop file from the AppImage
func (ai *AppImage) getEntry() (io.Reader, error) {
var r io.Reader
var r io.Reader
var err error

if ai.imageType == -2 {
Expand All @@ -360,13 +398,12 @@ func (ai *AppImage) getEntry() (io.Reader, error) {
r := entry.(*squashfs.File)

if r.IsSymlink() {
r = r .GetSymlinkFile()
r = r.GetSymlinkFile()
}

return r, err
}


return r, err
}

Expand All @@ -382,32 +419,34 @@ func (ai *AppImage) getArchitectures() ([]string, error) {
// If undefined in the desktop entry, assume arch via ELF AppImage runtime
if ai.Type() >= 0 {
e, err := elf.NewFile(ai.file)
if err != nil {return s, err}
if err != nil {
return s, err
}

switch e.Machine {
case elf.EM_386:
return []string{"i386"}, nil
case elf.EM_X86_64:
return []string{"x86_64"}, nil
case elf.EM_ARM:
return []string{"armhf"}, nil
case elf.EM_AARCH64:
return []string{"aarch64"}, nil
case elf.EM_386:
return []string{"i386"}, nil
case elf.EM_X86_64:
return []string{"x86_64"}, nil
case elf.EM_ARM:
return []string{"armhf"}, nil
case elf.EM_AARCH64:
return []string{"aarch64"}, nil
}
}

// Assume arch via shImg runtime
if ai.Type() < -1 {
scanner := bufio.NewScanner(ai.file)
scanner := bufio.NewScanner(ai.file)
arches := []string{}

counter := 0
for scanner.Scan() {
counter++
if strings.HasPrefix(scanner.Text(), "arch='") {
str := scanner.Text()
str = strings.ReplaceAll(str, "arch='", "")
str = strings.ReplaceAll(str, "'", "")
str := scanner.Text()
str = strings.ReplaceAll(str, "arch='", "")
str = strings.ReplaceAll(str, "'", "")
arches = helpers.SplitKey(str)
return arches, nil
}
Expand Down
Loading

0 comments on commit 490ab39

Please sign in to comment.