Skip to content

Commit 94eac53

Browse files
Check that team has certificates (#81)
* teamHasCertificates * PR clean - fix (+4 squashed commits) Squashed commits: [3fa4b0d] - [b3e302a] - [8e25678] - (+2 squashed commits) Squashed commits: [86e8e42] log fix [5439d32] PR clean - fix [b9572ef] No codesign cert find issue fix for the --certs-only flag * PR clean fix
1 parent 1d09a69 commit 94eac53

File tree

1 file changed

+104
-47
lines changed

1 file changed

+104
-47
lines changed

codesigndoc/codesigngroup.go

Lines changed: 104 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -68,83 +68,123 @@ func printCodesignGroup(group export.IosCodeSignGroup) {
6868
func collectIpaExportCertificate(archiveCertificate certificateutil.CertificateInfoModel, installedCertificates []certificateutil.CertificateInfoModel) (certificateutil.CertificateInfoModel, error) {
6969
fmt.Println()
7070
fmt.Println()
71-
question := fmt.Sprintf(`The archive used codesigning files of team: %s - %s
72-
Would you like to use this team to sign your project?`, archiveCertificate.TeamID, archiveCertificate.TeamName)
73-
useArchiveTeam, err := goinp.AskForBoolWithDefault(question, true)
74-
if err != nil {
75-
return certificateutil.CertificateInfoModel{}, fmt.Errorf("failed to read input: %s", err)
76-
}
7771

78-
selectedTeam := ""
79-
certificatesByTeam := mapCertificatesByTeam(installedCertificates)
72+
selectedCertificate := certificateutil.CertificateInfoModel{}
8073

81-
if !useArchiveTeam {
82-
teams := []string{}
83-
for team := range certificatesByTeam {
84-
teams = append(teams, team)
85-
}
74+
// Asking the user over and over until we find a valid certificate for the selected export method.
75+
for searchingValidCertificate := true; searchingValidCertificate; {
8676

87-
fmt.Println()
88-
selectedTeam, err = goinp.SelectFromStringsWithDefault("Select the Development team to sign your project", 1, teams)
77+
// Export method
78+
exportMethods := []string{"development", "app-store", "ad-hoc", "enterprise"}
79+
80+
selectedExportMethod, err := goinp.SelectFromStringsWithDefault("Select the ipa export method", 1, exportMethods)
8981
if err != nil {
9082
return certificateutil.CertificateInfoModel{}, fmt.Errorf("failed to read input: %s", err)
9183
}
92-
} else {
93-
selectedTeam = fmt.Sprintf("%s - %s", archiveCertificate.TeamID, archiveCertificate.TeamName)
94-
}
84+
log.Debugf("selected export method: %v", selectedExportMethod)
9585

96-
selectedCertificate := certificateutil.CertificateInfoModel{}
86+
// Export method needs Development or Distribution certificate?
87+
exportDistCert := true
88+
if selectedExportMethod == "development" {
89+
exportDistCert = false
90+
}
9791

98-
if isDistributionCertificate(archiveCertificate) {
99-
certificates := certificatesByTeam[selectedTeam]
100-
developmentCertificates := certificateutil.FilterCertificateInfoModelsByFilterFunc(certificates, func(certInfo certificateutil.CertificateInfoModel) bool {
101-
return !isDistributionCertificate(certInfo)
102-
})
92+
selectedTeam := ""
93+
log.Debugf("InstalledCerts: %v\n", installedCertificates)
10394

104-
certificateOptions := []string{}
105-
for _, certInfo := range developmentCertificates {
106-
certificateOption := fmt.Sprintf("%s [%s]", certInfo.CommonName, certInfo.Serial)
107-
certificateOptions = append(certificateOptions, certificateOption)
95+
// Filter the installed certificates by distribution type
96+
var certsForSelectedExport []certificateutil.CertificateInfoModel
97+
if exportDistCert {
98+
certsForSelectedExport = certificateutil.FilterCertificateInfoModelsByFilterFunc(installedCertificates, func(certInfo certificateutil.CertificateInfoModel) bool {
99+
return isDistributionCertificate(certInfo)
100+
})
101+
log.Debugf("Distribution certificated: %v\n", certsForSelectedExport)
102+
} else {
103+
certsForSelectedExport = certificateutil.FilterCertificateInfoModelsByFilterFunc(installedCertificates, func(certInfo certificateutil.CertificateInfoModel) bool {
104+
return !isDistributionCertificate(certInfo)
105+
})
106+
log.Debugf("Developer certificated: %v\n", certsForSelectedExport)
108107
}
109108

110-
fmt.Println()
111-
question := fmt.Sprintf(`The Xcode archive used distribution certificate: %s [%s].
112-
Please select a development certificate:`, archiveCertificate.CommonName, archiveCertificate.Serial)
113-
selectedCertificateOption, err := goinp.SelectFromStringsWithDefault(question, 1, certificateOptions)
114-
if err != nil {
115-
return certificateutil.CertificateInfoModel{}, fmt.Errorf("failed to read input: %s", err)
109+
filteredCertificatesByTeam := mapCertificatesByTeam(certsForSelectedExport)
110+
log.Debugf("Filtered certificates (by distribution type) by team: %v\n", filteredCertificatesByTeam)
111+
112+
if len(filteredCertificatesByTeam) == 0 {
113+
log.Warnf("🚨 We couldn't find any certificate for the %s export method.", selectedExportMethod)
114+
continue
116115
}
117116

118-
for _, certInfo := range developmentCertificates {
119-
certificateOption := fmt.Sprintf("%s [%s]", certInfo.CommonName, certInfo.Serial)
120-
if certificateOption == selectedCertificateOption {
121-
selectedCertificate = certInfo
117+
useArchiveTeam := true
118+
_, contains := filteredCertificatesByTeam[fmt.Sprintf("%s - %s", archiveCertificate.TeamID, archiveCertificate.TeamName)]
119+
120+
// Ask the question if there is multiple valid team and the archiving team is one of them.
121+
// Skip it if only 1 team has certificates on the machine. Or the archiving team does'n have the desired certificate type.
122+
// Skip the question + set the useArchiveTeam = false, if multiple team has certificate for the export method but the archiving team is not one of them.
123+
if len(filteredCertificatesByTeam) > 1 && contains {
124+
question := fmt.Sprintf(`The archive used codesigning files of team: %s - %s
125+
Would you like to use this team to export an ipa file?`, archiveCertificate.TeamID, archiveCertificate.TeamName)
126+
useArchiveTeam, err = goinp.AskForBoolWithDefault(question, true)
127+
if err != nil {
128+
return certificateutil.CertificateInfoModel{}, fmt.Errorf("failed to read input: %s", err)
122129
}
130+
// If multiple team has certificate for the export method but the archiving team is not one of them.
131+
} else if !contains {
132+
archiveTeam := fmt.Sprintf("%s - %s", archiveCertificate.TeamName, archiveCertificate.TeamID)
133+
134+
fmt.Println()
135+
log.Warnf("🚨 The archiving team (%s) doesn't have certificate for the %s export method", archiveTeam, selectedExportMethod)
136+
useArchiveTeam = false
137+
} else {
138+
archiveTeam := fmt.Sprintf("%s - %s", archiveCertificate.TeamName, archiveCertificate.TeamID)
139+
140+
fmt.Println()
141+
log.Printf("Only the archiving team (%s) has certificate for the %s export method", archiveTeam, selectedExportMethod)
142+
}
143+
144+
// Use different team for export than archive.
145+
if !useArchiveTeam {
146+
teams := []string{}
147+
for team := range filteredCertificatesByTeam {
148+
if hasCertificateForDistType(exportDistCert, filteredCertificatesByTeam[team]) {
149+
teams = append(teams, team)
150+
}
151+
}
152+
153+
fmt.Println()
154+
selectedTeam, err = goinp.SelectFromStringsWithDefault("Select the Development team to export your app", 1, teams)
155+
if err != nil {
156+
return certificateutil.CertificateInfoModel{}, fmt.Errorf("failed to read input: %s", err)
157+
}
158+
} else {
159+
selectedTeam = fmt.Sprintf("%s - %s", archiveCertificate.TeamID, archiveCertificate.TeamName)
123160
}
124-
} else {
125-
certificates := certificatesByTeam[selectedTeam]
126-
distributionCertificates := certificateutil.FilterCertificateInfoModelsByFilterFunc(certificates, func(certInfo certificateutil.CertificateInfoModel) bool {
127-
return isDistributionCertificate(certInfo)
128-
})
129161

162+
// Find the specific development certificate.
163+
filteredTeamCertificates := filteredCertificatesByTeam[selectedTeam]
130164
certificateOptions := []string{}
131-
for _, certInfo := range distributionCertificates {
165+
166+
for _, certInfo := range filteredTeamCertificates {
132167
certificateOption := fmt.Sprintf("%s [%s]", certInfo.CommonName, certInfo.Serial)
133168
certificateOptions = append(certificateOptions, certificateOption)
134169
}
135170

171+
certType := "distribution"
172+
if !exportDistCert {
173+
certType = "development"
174+
}
175+
136176
fmt.Println()
137-
question := fmt.Sprintf(`The Xcode archive used development certificate: %s [%s].
138-
Please select a distribution certificate:`, archiveCertificate.CommonName, archiveCertificate.Serial)
177+
question := fmt.Sprintf("Please select a %s certificate:", certType)
139178
selectedCertificateOption, err := goinp.SelectFromStringsWithDefault(question, 1, certificateOptions)
140179
if err != nil {
141180
return certificateutil.CertificateInfoModel{}, fmt.Errorf("failed to read input: %s", err)
142181
}
143182

144-
for _, certInfo := range distributionCertificates {
183+
for _, certInfo := range filteredTeamCertificates {
145184
certificateOption := fmt.Sprintf("%s [%s]", certInfo.CommonName, certInfo.Serial)
146185
if certificateOption == selectedCertificateOption {
147186
selectedCertificate = certInfo
187+
searchingValidCertificate = false
148188
}
149189
}
150190
}
@@ -367,3 +407,20 @@ func collectIpaExportSelectableCodeSignGroups(archive xcarchive.IosArchive, inst
367407

368408
return codeSignGroups
369409
}
410+
411+
// hasCertificateForDistType returns true if the provided certificate list has certificate for the selected cert type.
412+
// If isDistCert == true it will search for Distribution Certificates. If it's == false it will search for Developmenttion Certificates.
413+
// If the team doesn't have any certificate for the selected cert type, it will return false.
414+
func hasCertificateForDistType(isDistCert bool, certificates []certificateutil.CertificateInfoModel) bool {
415+
if !isDistCert {
416+
developmentCertificates := certificateutil.FilterCertificateInfoModelsByFilterFunc(certificates, func(certInfo certificateutil.CertificateInfoModel) bool {
417+
return !isDistributionCertificate(certInfo)
418+
})
419+
return len(developmentCertificates) > 0
420+
}
421+
422+
distributionCertificates := certificateutil.FilterCertificateInfoModelsByFilterFunc(certificates, func(certInfo certificateutil.CertificateInfoModel) bool {
423+
return isDistributionCertificate(certInfo)
424+
})
425+
return len(distributionCertificates) > 0
426+
}

0 commit comments

Comments
 (0)