Class: Pindo::CertHelper
- Inherits:
-
Object
- Object
- Pindo::CertHelper
- Defined in:
- lib/pindo/module/cert/cert_helper.rb
Class Method Summary collapse
-
.clean_git_certs(apple_id:, pindo_dir:, deploy_cert_giturl:, dev_cert_giturl:, demo_apple_id:) ⇒ Object
证书管理辅助方法 ======================================== 清理 Git 仓库中的证书.
-
.clean_local_certs ⇒ Object
清理本地证书 删除系统中所有的 Apple Development 和 Apple Distribution 证书 清理 Provisioning Profiles 文件夹.
-
.create_and_install_certs(cert_mode:, storage:, apple_id:, bundle_id_array:, cert_type:, platform_type:, project_dir: nil, match_flag: false) ⇒ Array<Hash>
创建并安装证书(门面方法).
-
.create_upload_cert_info(apple_id:, cert_type:, platform_type:) ⇒ Object
创建上传证书信息.
-
.create_upload_provisioning_info(apple_id:, cert_type:, platform_type:, provisioning_info_array:) ⇒ Hash
创建上传 Provisioning 信息.
-
.fetch_and_install_certs(cert_mode:, storage:, apple_id:, bundle_id_array:, cert_type:, platform_type:, project_dir: nil, match_flag: false) ⇒ Array<Hash>
获取并安装证书(门面方法).
- .install_and_config_certs(build_type:, platform_type: 'ios', project_dir: Dir.pwd) ⇒ Object
- .is_cert_valid?(cer_certificate_path) ⇒ Boolean
- .isMac? ⇒ Boolean
- .select_cert_or_key(paths:) ⇒ Object
Class Method Details
.clean_git_certs(apple_id:, pindo_dir:, deploy_cert_giturl:, dev_cert_giturl:, demo_apple_id:) ⇒ Object
证书管理辅助方法
清理 Git 仓库中的证书
117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 |
# File 'lib/pindo/module/cert/cert_helper.rb', line 117 def clean_git_certs(apple_id:, pindo_dir:, deploy_cert_giturl:, dev_cert_giturl:, demo_apple_id:) require_relative '../../base/git_handler' # 确定使用哪个 Git URL git_url = apple_id.eql?(demo_apple_id) ? dev_cert_giturl : deploy_cert_giturl puts "正在清理 Git 仓库中的证书..." puts "Apple ID: #{apple_id}" puts "Git URL: #{git_url}" # 克隆或更新证书仓库 cert_repo_dir = Pindo::GitHandler.getcode_to_dir( reponame: Pindo::GitHandler.get_repo_base_name(repo_url: git_url), remote_url: git_url, path: pindo_dir, new_branch: apple_id ) # 删除 certs 和 profiles 目录 certs_dir = File.join(cert_repo_dir, "certs") profiles_dir = File.join(cert_repo_dir, "profiles") FileUtils.rm_rf(certs_dir) if File.exist?(certs_dir) FileUtils.rm_rf(profiles_dir) if File.exist?(profiles_dir) puts "✓ 已删除 certs 和 profiles 目录" # 提交并推送到远程仓库 Pindo::GitHandler.prepare_gitenv() Pindo::GitHandler.git_addpush_repo(path: cert_repo_dir, message: "remove #{apple_id} certs") puts "✓ Git 仓库证书清理完成" end |
.clean_local_certs ⇒ Object
清理本地证书删除系统中所有的 Apple Development 和 Apple Distribution 证书清理 Provisioning Profiles 文件夹
154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 |
# File 'lib/pindo/module/cert/cert_helper.rb', line 154 def clean_local_certs puts "正在清理本地证书..." # 获取所有代码签名证书 output, _ = Open3.capture2('security find-identity -p codesigning') identity_ids_0 = [] identity_ids_1 = output.split("\n").map { |line| line.split(' ')[1] if line.include?('Apple Development') }.compact identity_ids_2 = output.split("\n").map { |line| line.split(' ')[1] if line.include?('Apple Distribution') }.compact identity_ids = identity_ids_0 + identity_ids_1 + identity_ids_2 identity_ids = identity_ids.uniq puts "找到 #{identity_ids.size} 个证书:" puts identity_ids # 删除证书 identity_ids.each do |identity_id| system "security delete-certificate -Z #{identity_id}" end # 清理 Provisioning Profiles profile_file_dir = File.("~/Library/MobileDevice") profile_file_path = File.join(profile_file_dir, "Provisioning Profiles") if File.exist?(profile_file_path) FileUtils.rm_rf(profile_file_path) puts "✓ 已清理 Provisioning Profiles 文件夹" end puts "✓ 本地证书清理完成" end |
.create_and_install_certs(cert_mode:, storage:, apple_id:, bundle_id_array:, cert_type:, platform_type:, project_dir: nil, match_flag: false) ⇒ Array<Hash>
创建并安装证书(门面方法)
这是创建证书的统一入口,会根据 cert_mode 和 storage 参数自动选择合适的证书操作类(CertOperator)来执行具体操作
40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
# File 'lib/pindo/module/cert/cert_helper.rb', line 40 def create_and_install_certs( cert_mode:, storage:, apple_id:, bundle_id_array:, cert_type:, platform_type:, project_dir: nil, match_flag: false ) # 选择合适的证书操作类 operator = determine_cert_operator( cert_mode: cert_mode, storage: storage, match_flag: match_flag ) # 调用具体的操作类执行创建和安装 operator.create_and_install_certs( apple_id: apple_id, bundle_id_array: bundle_id_array, cert_type: cert_type, platform_type: platform_type, project_dir: project_dir ) end |
.create_upload_cert_info(apple_id:, cert_type:, platform_type:) ⇒ Object
创建上传证书信息
249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 |
# File 'lib/pindo/module/cert/cert_helper.rb', line 249 def create_upload_cert_info(apple_id:, cert_type:, platform_type:) pindo_single_config = Pindoconfig.instance cert_dest_dir = File.join(Dir.pwd, "cert") FileUtils.mkdir_p(cert_dest_dir) unless File.exist?(cert_dest_dir) cert_type_temp = cert_type cert_sub_dir = cert_type.downcase # 确定证书子目录 if platform_type.downcase.eql?("macos") if cert_type.downcase.include?("development") cert_sub_dir = "development" elsif cert_type.downcase.eql?("appstore") cert_sub_dir = "distribution" elsif cert_type.downcase.eql?("developer_id") cert_type_temp = "developer_id" cert_sub_dir = "developer_id_application" else # 向后兼容:adhoc → developer_id cert_type_temp = "developer_id" cert_sub_dir = "developer_id_application" end else cert_sub_dir = "distribution" unless cert_type.downcase.include?("development") end # 确定 Git URL cert_git_url = apple_id.eql?(pindo_single_config.demo_apple_id) ? pindo_single_config.dev_cert_giturl : pindo_single_config.deploy_cert_giturl # 克隆证书仓库 cert_reponame = cert_git_url.split("/").last.chomp(".git") certs_dir = Pindo::GitHandler.getcode_to_dir( reponame: cert_reponame, remote_url: cert_git_url, path: pindo_single_config.pindo_dir, new_branch: apple_id ) # 查找密钥文件 keys = Dir[File.join(certs_dir, "certs", cert_sub_dir, "*.p12")] decrypt_password = AESHelper.get_password(keychain_name: cert_git_url) output_dir = Dir.mktmpdir begin key_path = AESHelper.decrypt_specific_file( src_file: keys.first, password: decrypt_password, output_dir: output_dir ) rescue Informative => e AESHelper.delete_password(keychain_name: cert_git_url) AESHelper.clear_password_cache_for(keychain_name: cert_git_url) raise Informative, "密钥解析失败,已清除错误的密码,请重新运行输入正确的密码" end # 解密成功,保存密码到 Keychain begin AESHelper.store_password(keychain_name: cert_git_url, password: decrypt_password) Funlog.instance.("密钥解密成功,密码已保存到Keychain") rescue => e Funlog.instance.("密码保存到Keychain失败: #{e.}") Funlog.instance.("下次使用时需要重新输入密码") end FileUtils.copy(key_path, File.join(cert_dest_dir, "#{cert_type_temp}.p12")) end |
.create_upload_provisioning_info(apple_id:, cert_type:, platform_type:, provisioning_info_array:) ⇒ Hash
创建上传 Provisioning 信息
325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 |
# File 'lib/pindo/module/cert/cert_helper.rb', line 325 def create_upload_provisioning_info(apple_id:, cert_type:, platform_type:, provisioning_info_array:) cert_dir = File.join(Dir.pwd, "cert") cert_json_file = File.join(cert_dir, "certs.json") FileUtils.mkdir_p(cert_dir) unless File.exist?(cert_dir) # 读取现有 cert.json cert_json = [] begin cert_json = JSON.parse(File.read(cert_json_file)) if File.exist?(cert_json_file) cert_json ||= [] rescue StandardError => e cert_json = [] end # 获取基本信息 bundle_id = provisioning_info_array.select { |s| s["type"].to_s.eql?("bundle_id") }.first["bundle_id"] team_id_value = provisioning_info_array.first["team_id"] bundle_id_signing_identity = provisioning_info_array.first["signing_identity"] # 查找或创建账号证书集 account_cert_set = {} select_result = cert_json.select { |x| x["account_name"].eql?(apple_id) }.first if select_result.nil? account_cert_set = {} else account_cert_set = select_result cert_json.delete_if { |x| x["account_name"].eql?(apple_id) } end account_cert_set["account_name"] = apple_id account_cert_set["team_id"] = team_id_value account_cert_set["certs"] = account_cert_set["certs"] || [] # 查找或创建证书项 cert_item = {} cert_item_result = account_cert_set["certs"].select { |x| x["cert_id"].eql?(bundle_id_signing_identity) }.first if cert_item_result.nil? cert_item = {} else cert_item = cert_item_result account_cert_set["certs"].delete_if { |x| x["cert_id"].eql?(bundle_id_signing_identity) } end # 确定 provision_start_name provision_start_name = "Development" cert_type_temp = cert_type if platform_type.downcase.include?("macos") if cert_type.downcase.include?("development") provision_start_name = "development" elsif cert_type.downcase.eql?("appstore") provision_start_name = "appstore" elsif cert_type.downcase.eql?("developer_id") cert_type_temp = "developer_id" provision_start_name = "direct" else # 向后兼容:adhoc → developer_id cert_type_temp = "developer_id" provision_start_name = "direct" end else if cert_type.downcase.include?("development") provision_start_name = "development" elsif cert_type.downcase.include?("adhoc") provision_start_name = "adhoc" else provision_start_name = "appstore" end end # 设置证书项 cert_item["cert_id"] = cert_item["cert_id"] || bundle_id_signing_identity cert_item["password"] = "goodcert1" cert_item["cert_file"] = "#{cert_type_temp}.p12" cert_item["cert_type"] = cert_type_temp cert_item["cert_provisioning_group"] = cert_item["cert_provisioning_group"] || [] # 查找或创建 provisioning group cert_provisioning_group_item = {} provisioning_group_id = [cert_type_temp, platform_type, bundle_id].join("_") provisioning_group_result = cert_item["cert_provisioning_group"].select { |x| x["provisioning_group_id"].eql?(provisioning_group_id) }.first if provisioning_group_result.nil? cert_provisioning_group_item = {} else cert_provisioning_group_item = provisioning_group_result cert_item["cert_provisioning_group"].delete_if { |x| x["provisioning_group_id"].eql?(provisioning_group_id) } end cert_provisioning_group_item["provisioning_group_id"] = provisioning_group_id cert_provisioning_group_item["platform_type"] = platform_type cert_provisioning_group_item["provisioning_main_bundle_id"] = bundle_id cert_provisioning_group_item["provisioning_items"] = [] group_id = [provision_start_name, platform_type, bundle_id].join("_") # 处理每个 provisioning profile provisioning_info_array.each do |provisioning_info| bundle_id_temp = provisioning_info['bundle_id'] provisioning_id = [provision_start_name, bundle_id_temp].join("_") real_path = provisioning_info["profile_path"] extname = File.extname(real_path) cert_provisioning_group_item["provisioning_items"] << { "bundle_id" => bundle_id_temp, "provisioning_id" => provisioning_id, "group_id" => group_id, "provisioning_file" => provisioning_id + extname } FileUtils.cp_r(real_path, File.join(cert_dir, provisioning_id + extname)) end # 组装最终结果 cert_item["cert_provisioning_group"] << cert_provisioning_group_item account_cert_set["certs"] << cert_item cert_json << account_cert_set # 写入 JSON 文件 File.open(cert_json_file, "w") do |f| f.write(JSON.pretty_generate(cert_json.compact)) end account_cert_set end |
.fetch_and_install_certs(cert_mode:, storage:, apple_id:, bundle_id_array:, cert_type:, platform_type:, project_dir: nil, match_flag: false) ⇒ Array<Hash>
获取并安装证书(门面方法)
这是获取证书的统一入口,会根据 cert_mode 和 storage 参数自动选择合适的证书操作类(CertOperator)来执行具体操作
81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 |
# File 'lib/pindo/module/cert/cert_helper.rb', line 81 def fetch_and_install_certs( cert_mode:, storage:, apple_id:, bundle_id_array:, cert_type:, platform_type:, project_dir: nil, match_flag: false ) # 选择合适的证书操作类 operator = determine_cert_operator( cert_mode: cert_mode, storage: storage, match_flag: match_flag ) # 调用具体的操作类执行获取和安装 operator.fetch_and_install_certs( apple_id: apple_id, bundle_id_array: bundle_id_array, cert_type: cert_type, platform_type: platform_type, project_dir: project_dir ) end |
.install_and_config_certs(build_type:, platform_type: 'ios', project_dir: Dir.pwd) ⇒ Object
200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 |
# File 'lib/pindo/module/cert/cert_helper.rb', line 200 def install_and_config_certs(build_type:, platform_type: 'ios', project_dir: Dir.pwd) # 标准化构建类型 cert_type = Pindo::Options::BuildOptions.normalize_build_type(build_type) # 使用 IosConfigParser 单例 require 'pindo/config/ios_config_parser' config_parser = Pindo::IosConfigParser.instance # 检查配置是否已加载 if config_parser.config_json.nil? raise Informative, "install_and_config_certs 方法中,配置未加载 config.json" end apple_id = config_parser.apple_id bundle_id_array = config_parser.get_bundle_id_array # 根据 build_type 决定存储方式 # - appstore: 使用 Git 存储(严格版本控制) # - dev/adhoc: 使用 HTTPS 存储(快速便捷) storage_mode = (cert_type == 'appstore') ? 'git' : 'https' # 调用 fetch_and_install_certs provisioning_info_array = fetch_and_install_certs( cert_mode: 'custom', storage: storage_mode, apple_id: apple_id, bundle_id_array: bundle_id_array, cert_type: cert_type, platform_type: platform_type, project_dir: project_dir, match_flag: false ) team_id = provisioning_info_array.first["team_id"] { provisioning_info_array: provisioning_info_array, team_id: team_id } end |
.is_cert_valid?(cer_certificate_path) ⇒ Boolean
189 190 191 192 193 |
# File 'lib/pindo/module/cert/cert_helper.rb', line 189 def is_cert_valid?(cer_certificate_path) cert = OpenSSL::X509::Certificate.new(File.binread(cer_certificate_path)) now = Time.now.utc return (now <=> cert.not_after) == -1 end |
.isMac? ⇒ Boolean
195 196 197 |
# File 'lib/pindo/module/cert/cert_helper.rb', line 195 def isMac? (/darwin/ =~ RUBY_PLATFORM) != nil end |
.select_cert_or_key(paths:) ⇒ Object
184 185 186 187 |
# File 'lib/pindo/module/cert/cert_helper.rb', line 184 def select_cert_or_key(paths:) cert_id_path = ENV['MATCH_CERTIFICATE_ID'] ? paths.find { |path| path.include?(ENV['MATCH_CERTIFICATE_ID']) } : nil cert_id_path || paths.last end |