Source file misc/ios/detect.go

     1  // Copyright 2015 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  //go:build ignore
     6  
     7  // detect attempts to autodetect the correct
     8  // values of the environment variables
     9  // used by go_ios_exec.
    10  // detect shells out to ideviceinfo, a third party program that can
    11  // be obtained by following the instructions at
    12  // https://github.com/libimobiledevice/libimobiledevice.
    13  package main
    14  
    15  import (
    16  	"bytes"
    17  	"crypto/x509"
    18  	"fmt"
    19  	"os"
    20  	"os/exec"
    21  	"strings"
    22  )
    23  
    24  func main() {
    25  	udids := getLines(exec.Command("idevice_id", "-l"))
    26  	if len(udids) == 0 {
    27  		fail("no udid found; is a device connected?")
    28  	}
    29  
    30  	mps := detectMobileProvisionFiles(udids)
    31  	if len(mps) == 0 {
    32  		fail("did not find mobile provision matching device udids %q", udids)
    33  	}
    34  
    35  	fmt.Println("# Available provisioning profiles below.")
    36  	fmt.Println("# NOTE: Any existing app on the device with the app id specified by GOIOS_APP_ID")
    37  	fmt.Println("# will be overwritten when running Go programs.")
    38  	for _, mp := range mps {
    39  		fmt.Println()
    40  		f, err := os.CreateTemp("", "go_ios_detect_")
    41  		check(err)
    42  		fname := f.Name()
    43  		defer os.Remove(fname)
    44  
    45  		out := output(parseMobileProvision(mp))
    46  		_, err = f.Write(out)
    47  		check(err)
    48  		check(f.Close())
    49  
    50  		cert, err := plistExtract(fname, "DeveloperCertificates:0")
    51  		check(err)
    52  		pcert, err := x509.ParseCertificate(cert)
    53  		check(err)
    54  		fmt.Printf("export GOIOS_DEV_ID=\"%s\"\n", pcert.Subject.CommonName)
    55  
    56  		appID, err := plistExtract(fname, "Entitlements:application-identifier")
    57  		check(err)
    58  		fmt.Printf("export GOIOS_APP_ID=%s\n", appID)
    59  
    60  		teamID, err := plistExtract(fname, "Entitlements:com.apple.developer.team-identifier")
    61  		check(err)
    62  		fmt.Printf("export GOIOS_TEAM_ID=%s\n", teamID)
    63  	}
    64  }
    65  
    66  func detectMobileProvisionFiles(udids [][]byte) []string {
    67  	cmd := exec.Command("mdfind", "-name", ".mobileprovision")
    68  	lines := getLines(cmd)
    69  
    70  	var files []string
    71  	for _, line := range lines {
    72  		if len(line) == 0 {
    73  			continue
    74  		}
    75  		xmlLines := getLines(parseMobileProvision(string(line)))
    76  		matches := 0
    77  		for _, udid := range udids {
    78  			for _, xmlLine := range xmlLines {
    79  				if bytes.Contains(xmlLine, udid) {
    80  					matches++
    81  				}
    82  			}
    83  		}
    84  		if matches == len(udids) {
    85  			files = append(files, string(line))
    86  		}
    87  	}
    88  	return files
    89  }
    90  
    91  func parseMobileProvision(fname string) *exec.Cmd {
    92  	return exec.Command("security", "cms", "-D", "-i", string(fname))
    93  }
    94  
    95  func plistExtract(fname string, path string) ([]byte, error) {
    96  	out, err := exec.Command("/usr/libexec/PlistBuddy", "-c", "Print "+path, fname).CombinedOutput()
    97  	if err != nil {
    98  		return nil, err
    99  	}
   100  	return bytes.TrimSpace(out), nil
   101  }
   102  
   103  func getLines(cmd *exec.Cmd) [][]byte {
   104  	out := output(cmd)
   105  	lines := bytes.Split(out, []byte("\n"))
   106  	// Skip the empty line at the end.
   107  	if len(lines[len(lines)-1]) == 0 {
   108  		lines = lines[:len(lines)-1]
   109  	}
   110  	return lines
   111  }
   112  
   113  func output(cmd *exec.Cmd) []byte {
   114  	out, err := cmd.Output()
   115  	if err != nil {
   116  		fmt.Println(strings.Join(cmd.Args, "\n"))
   117  		fmt.Fprintln(os.Stderr, err)
   118  		os.Exit(1)
   119  	}
   120  	return out
   121  }
   122  
   123  func check(err error) {
   124  	if err != nil {
   125  		fail(err.Error())
   126  	}
   127  }
   128  
   129  func fail(msg string, v ...interface{}) {
   130  	fmt.Fprintf(os.Stderr, msg, v...)
   131  	fmt.Fprintln(os.Stderr)
   132  	os.Exit(1)
   133  }
   134  

View as plain text