Skip to content

Commit

Permalink
Merge pull request #7 from nowsecure/feat/apps
Browse files Browse the repository at this point in the history
feat: add installation.Apps function to get apps from lockdown
  • Loading branch information
dylanhitt committed Jan 30, 2024
2 parents 8a72282 + 9771474 commit cd145ff
Show file tree
Hide file tree
Showing 3 changed files with 170 additions and 115 deletions.
124 changes: 105 additions & 19 deletions installation/installation.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,26 +3,28 @@ package installation
// #cgo pkg-config: libimobiledevice-1.0
// #include <stdlib.h>
// #include <libimobiledevice/installation_proxy.h>
// #include <plist/plist.h>
//
// void instproxy_client_options_add_pair(plist_t client_opts, char * key, char * value)
// {
// instproxy_client_options_add(client_opts, key, value, NULL);
// }
import "C"
import (
"errors"
"fmt"
"unsafe"

"github.com/nowsecure/goidevice/idevice"
"github.com/nowsecure/goidevice/plist"
)

// Proxy is an installation proxy
type Proxy interface {
Browse(clientOptions plist.PList) (plist.PList, error)
Close() error
}

type proxy struct {
p C.instproxy_client_t
type Proxy struct {
instproxy_client C.instproxy_client_t
}

// NewClientStartService creates a installation proxy
func NewClientStartService(device idevice.Device, label string) (Proxy, error) {
func NewClientStartService(device idevice.Device, label string) (*Proxy, error) {
labelC := C.CString(label)
defer C.free(unsafe.Pointer(labelC))

Expand All @@ -31,19 +33,103 @@ func NewClientStartService(device idevice.Device, label string) (Proxy, error) {
if err != nil {
return nil, err
}
return &proxy{p}, nil
return &Proxy{p}, nil
}

func (s *Proxy) Browse(opts *ClientOptions) (*plist.PList, error) {
var apps C.plist_t
err := resultToError(C.instproxy_browse(s.instproxy_client, (C.plist_t)(&opts.client_opts.P), &apps))
if err != nil {
return nil, err
}

list, err := plist.FromPointer(unsafe.Pointer(apps))
if err != nil {
return nil, err
}
if list.Type() != plist.PListTypeArray {
return nil, errors.New("instproxy_browse returned an invalid plist, must be an array")
}

return list, err
}

func (s *Proxy) Free() error {
return resultToError(C.instproxy_client_free(s.instproxy_client))
}

type AppScope string

const (
User AppScope = "User"
System AppScope = "System"
All AppScope = ""
)

type App struct {
ID string
Name string
Version string
}

func (s *proxy) Browse(clientOptions plist.PList) (plist.PList, error) {
var p C.plist_t
err := resultToError(C.instproxy_browse(s.p, (C.plist_t)(plist.GetPointer(clientOptions)), &p))
return plist.FromPointer(unsafe.Pointer(p)), err
func (a *App) String() string {
return fmt.Sprintf("Identifier: %s, Name: %s, Version: %s", a.ID, a.Name, a.Version)
}

func (s *proxy) Close() error {
err := resultToError(C.instproxy_client_free(s.p))
if err == nil {
s.p = nil
// Apps returns an array of App
func (s *Proxy) Apps(scope AppScope) ([]App, error) {
opts := NewClientOptions()
defer opts.Free()
if scope != All {
opts.AddOption("ApplicationType", string(scope))
}

appsPList, err := s.Browse(opts)
if err != nil {
return nil, err
}
defer appsPList.Free()

apps := []App{}
for i := 0; i < appsPList.ArraySize(); i++ {
item := appsPList.ArrayItem(i)
id, _ := item.GetItem("CFBundleIdentifier")
name, _ := item.GetItem("CFBundleDisplayName")
version, _ := item.GetItem("CFBundleShortVersionString")
apps = append(apps, App{
ID: id.String(),
Name: name.String(),
Version: version.String(),
})
}
return err

return apps, nil
}

type ClientOptions struct {
client_opts *plist.PList
}

func NewClientOptions() *ClientOptions {
opts := C.instproxy_client_options_new()
return &ClientOptions{(*plist.PList)(opts)}
}

func (c *ClientOptions) AddOption(key, value string) {
keyC := C.CString(key)
valueC := C.CString(value)
defer C.free(unsafe.Pointer(keyC))
defer C.free(unsafe.Pointer(valueC))

C.instproxy_client_options_add_pair((C.plist_t)(c.client_opts), keyC, valueC)
}

func (c *ClientOptions) RemoveOption(key string) {
keyC := C.CString(key)
defer C.free(unsafe.Pointer(keyC))
c.client_opts.RemoveItem(key)
}

func (c *ClientOptions) Free() {
c.client_opts.Free()
}
11 changes: 5 additions & 6 deletions lockdown/lockdown.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ package lockdown
// #include <libimobiledevice/lockdown.h>
import "C"
import (
"errors"
"unsafe"

"github.com/nowsecure/goidevice/idevice"
Expand All @@ -18,7 +17,7 @@ type Client interface {
Pair() error
ValidatePair() error
DeviceName() (string, error)
PList(domain string) (plist.PList, error)
PList(domain string) (*plist.PList, error)
Close() error
}

Expand Down Expand Up @@ -74,7 +73,7 @@ func (s *client) DeviceName() (string, error) {
return C.GoString(p), err
}

func (s *client) PList(domain string) (plist.PList, error) {
func (s *client) PList(domain string) (*plist.PList, error) {
var domainC *C.char = nil

if domain != "" {
Expand All @@ -88,9 +87,9 @@ func (s *client) PList(domain string) (plist.PList, error) {
return nil, err
}

list := plist.FromPointer(unsafe.Pointer(node))
if list == nil {
return nil, errors.New("no plist was found for the query")
list, err := plist.FromPointer(unsafe.Pointer(node))
if err != nil {
return nil, err
}

return list, nil
Expand Down
Loading

0 comments on commit cd145ff

Please sign in to comment.