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

View as plain text