fastlane-plugin-pgyer 0.3.2 → 0.3.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4aab71c4ccfbd932cce469d005c061664e6ca70b45969513fb811ded4c668562
4
- data.tar.gz: 20c05f3049146a01bf0913df72d85289df1f2a1d4753bfdd6447a4a73a68ee2d
3
+ metadata.gz: 76598ee4c500e69dc2628a463315f2b45ece7db0bebca38e26b65a9d8f3413cc
4
+ data.tar.gz: b2df8a60da19d648c964dbd92da17a50edd471a5343867afb6be2c56553dd721
5
5
  SHA512:
6
- metadata.gz: 5f6df6193af437a950c61ba737e19bee1282b71c0bc2fb8fabfb151c6928bf44ca6d34acf668e4d64a342704aa74f7dce76f0f2d0f60d81c4061473854e3d541
7
- data.tar.gz: f678c0607a076a3df8ba0315316fa0bf8278a4a3b109e1fb448a6298f5b50c4c33a7bb8c9549a01553331cd12c6841748f67dcaf8ac4b13277c26769503eeb3d
6
+ metadata.gz: 60302c4a4e3c101df47ed239c8c2a012fe161a3535d70ceb4f9047b94bd1e7f312eb8eb8e5b5f0fe39deae53b43299d312d8dc0c9d87f883911fc1e2379d94e3
7
+ data.tar.gz: 27415b535fa5f9110ecf86f145aa8499c8290c2abf3bf215175e1a31da517e28f384843e7caaafce192d2fc448d0f1034a6ef6207960b447b07f59890b977883
@@ -1,5 +1,6 @@
1
1
  require "faraday"
2
2
  require "faraday_middleware"
3
+ require "timeout"
3
4
 
4
5
  module Fastlane
5
6
  module Actions
@@ -74,18 +75,9 @@ module Fastlane
74
75
  },
75
76
  }
76
77
 
77
- api_host = "https://www.pgyer.com/apiv2/app"
78
-
79
- pgyer_client = Faraday.new(nil, conn_options) do |c|
80
- c.request :multipart
81
- c.request :url_encoded
82
- c.response :json, content_type: /\bjson$/
83
- c.adapter :net_http
84
- end
85
-
86
- response = pgyer_client.post "#{api_host}/getCOSToken", request_params
87
-
88
- info = response.body
78
+ # 选择可用的 API 域名
79
+ use_doh = params[:doh] == true
80
+ api_host, pgyer_client, info = self.select_available_api_host(conn_options, request_params, use_doh)
89
81
 
90
82
  if info["code"] != 0
91
83
  UI.user_error!("Get token is failed, info: #{info}")
@@ -121,7 +113,16 @@ module Fastlane
121
113
  UI.user_error!("PGYER Plugin Upload Error: #{response.body}")
122
114
  end
123
115
 
124
- answer = self.checkPublishStatus(pgyer_client, api_host, api_key, key)
116
+ # 如果使用 DoH,需要传递 DoH 相关信息
117
+ doh_info = nil
118
+ if use_doh && api_host.include?("www.pgyer.com")
119
+ domain = "www.pgyer.com"
120
+ ip_address = resolve_domain_via_doh(domain)
121
+ if ip_address
122
+ doh_info = { domain: domain, ip_address: ip_address }
123
+ end
124
+ end
125
+ answer = self.checkPublishStatus(pgyer_client, api_host, api_key, key, doh_info)
125
126
 
126
127
  if params[:save_uploaded_info_json]
127
128
  File.open("pgyer-fastlane-uploaded-app-info.json", "w") do |f|
@@ -181,7 +182,7 @@ module Fastlane
181
182
  end),
182
183
  FastlaneCore::ConfigItem.new(key: :hap,
183
184
  env_name: "PGYER_HAP",
184
- description: "Path to your HAP file. Optional if you use the _gym_ or _xcodebuild_ action. For Mac zip the .app. For Android provide path to .apk file",
185
+ description: "Path to your HAP file",
185
186
  default_value: Actions.lane_context[:HVIGOR_HAP_OUTPUT_PATH],
186
187
  optional: true,
187
188
  verify_block: proc do |value|
@@ -248,6 +249,12 @@ module Fastlane
248
249
  description: "Need to update the specified channel of the download short link, can specify only one channel, string type, such as: ABCD",
249
250
  optional: true,
250
251
  type: String),
252
+ FastlaneCore::ConfigItem.new(key: :doh,
253
+ env_name: "PGYER_DOH",
254
+ description: "Use DNS over HTTPS (DoH) to resolve domain names, bypassing local DNS. Experimental feature",
255
+ optional: true,
256
+ default_value: false,
257
+ type: Boolean),
251
258
  ]
252
259
  end
253
260
 
@@ -261,6 +268,193 @@ module Fastlane
261
268
 
262
269
  private
263
270
 
271
+ def self.select_available_api_host(conn_options, request_params, use_doh = false)
272
+ # 如果启用 DoH,直接使用 DoH 解析 www.pgyer.com,跳过三个域名测试
273
+ if use_doh
274
+ return select_api_host_via_doh(conn_options, request_params)
275
+ end
276
+
277
+ # 尝试多个域名,防止 DNS 劫持
278
+ api_hosts = [
279
+ "https://www.pgyer.com/apiv2/app",
280
+ "https://www.xcxwo.com/apiv2/app",
281
+ "https://www.pgyerapp.com/apiv2/app",
282
+ ]
283
+
284
+ api_host = nil
285
+ pgyer_client = nil
286
+ info = nil
287
+
288
+ api_hosts.each_with_index do |host, index|
289
+ UI.message "尝试使用域名 #{index + 1}/#{api_hosts.length}: #{host}"
290
+
291
+ begin
292
+ # 为域名检测设置 5 秒超时
293
+ test_conn_options = {
294
+ request: {
295
+ timeout: 5,
296
+ open_timeout: 5,
297
+ },
298
+ }
299
+ test_client = create_faraday_client(test_conn_options, nil)
300
+
301
+ # 使用超时控制,5 秒后如果还没响应就放弃
302
+ test_response = nil
303
+ test_info = nil
304
+
305
+ begin
306
+ Timeout.timeout(5) do
307
+ test_response = test_client.post "#{host}/getCOSToken", request_params
308
+ test_info = test_response.body
309
+ end
310
+ rescue Timeout::Error
311
+ UI.message "域名 #{host} 请求超时(5秒),切换到下一个域名"
312
+ next
313
+ end
314
+
315
+ # 检查响应是否有效:如果返回了有效的 JSON 且包含 code 字段,说明域名解析正常
316
+ if test_info && test_info.is_a?(Hash) && test_info.key?("code")
317
+ if test_info["code"] == 0
318
+ # API 调用成功,使用该域名
319
+ # 使用原始的超时设置重新创建客户端(用于后续上传)
320
+ api_host = host
321
+ pgyer_client = create_faraday_client(conn_options, nil)
322
+ info = test_info
323
+ UI.success "成功使用域名: #{host}"
324
+ break
325
+ else
326
+ # API 返回了业务错误,但域名解析正常
327
+ # 保存第一个可用的域名作为备选,继续尝试其他域名看是否有返回 code == 0 的
328
+ if api_host.nil?
329
+ api_host = host
330
+ # 使用原始的超时设置重新创建客户端
331
+ pgyer_client = create_faraday_client(conn_options, nil)
332
+ info = test_info
333
+ UI.message "域名 #{host} 解析正常,但 API 返回错误,保存为备选: #{test_info}"
334
+ else
335
+ UI.message "域名 #{host} 可用,但 API 返回错误: #{test_info}"
336
+ end
337
+ end
338
+ else
339
+ # 响应格式不正确,可能是 DNS 劫持
340
+ UI.message "域名 #{host} 返回的响应格式不正确,可能遭遇 DNS 劫持"
341
+ end
342
+ rescue => e
343
+ UI.message "域名 #{host} 测试失败(可能是 DNS 劫持或超时): #{e.message}"
344
+ next
345
+ end
346
+ end
347
+
348
+ if api_host.nil? || pgyer_client.nil? || info.nil?
349
+ UI.user_error!("所有域名都无法使用,可能都遭遇了 DNS 劫持。尝试的域名: #{api_hosts.join(', ')}")
350
+ end
351
+
352
+ return api_host, pgyer_client, info
353
+ end
354
+
355
+ # DoH 模式:使用 DoH 解析 www.pgyer.com(实验性功能)
356
+ def self.select_api_host_via_doh(conn_options, request_params)
357
+ UI.message "启用 DoH 模式,使用 DoH 解析 www.pgyer.com"
358
+
359
+ host = "https://www.pgyer.com/apiv2/app"
360
+ domain = "www.pgyer.com"
361
+
362
+ # 通过 DoH 解析域名
363
+ ip_address = resolve_domain_via_doh(domain)
364
+
365
+ if ip_address.nil?
366
+ UI.user_error!("DoH 解析失败,无法获取 www.pgyer.com 的 IP 地址")
367
+ end
368
+
369
+ UI.message "DoH 解析成功: #{domain} -> #{ip_address}"
370
+
371
+ # 使用 IP 地址替换域名,但保留 Host header
372
+ actual_url = host.gsub(domain, ip_address)
373
+ host_header = domain
374
+
375
+ begin
376
+ test_client = create_faraday_client(conn_options, host_header)
377
+
378
+ # 设置 Host header
379
+ request_headers = { "Host" => host_header }
380
+
381
+ test_response = test_client.post "#{actual_url}/getCOSToken", request_params, request_headers
382
+ test_info = test_response.body
383
+
384
+ if test_info && test_info.is_a?(Hash) && test_info.key?("code")
385
+ if test_info["code"] == 0
386
+ UI.success "DoH 模式:成功使用域名 #{host}"
387
+ return host, test_client, test_info
388
+ else
389
+ UI.user_error!("DoH 模式:API 返回错误: #{test_info}")
390
+ end
391
+ else
392
+ UI.user_error!("DoH 模式:返回的响应格式不正确: #{test_info}")
393
+ end
394
+ rescue => e
395
+ UI.user_error!("DoH 模式:请求失败: #{e.message}")
396
+ end
397
+ end
398
+
399
+ # DoH 相关方法(实验性功能)
400
+ def self.resolve_domain_via_doh(domain)
401
+ # 使用阿里云公共 DoH 服务
402
+ doh_url = "https://dns.alidns.com/resolve"
403
+
404
+ begin
405
+ doh_client = Faraday.new do |c|
406
+ c.request :url_encoded
407
+ c.response :json
408
+ c.adapter :net_http
409
+ end
410
+
411
+ response = doh_client.get(doh_url, { name: domain, type: "A" })
412
+ result = response.body
413
+
414
+ if result && result.is_a?(Hash) && result["Answer"]
415
+ # 获取第一个 A 记录
416
+ a_record = result["Answer"].find { |r| r["type"] == 1 }
417
+ if a_record && a_record["data"]
418
+ return a_record["data"]
419
+ end
420
+ end
421
+ rescue => e
422
+ UI.message "DoH 解析出错: #{e.message}"
423
+ end
424
+
425
+ return nil
426
+ end
427
+
428
+ def self.extract_domain_from_url(url)
429
+ # 从 URL 中提取域名
430
+ # 例如: https://www.pgyer.com/apiv2/app -> www.pgyer.com
431
+ uri = URI.parse(url)
432
+ return uri.host
433
+ end
434
+
435
+ def self.create_faraday_client(conn_options, host_header = nil)
436
+ # 创建基础的 Faraday 客户端
437
+ # Host header 将在请求时通过 headers 参数设置
438
+ # DoH 模式下禁用 SSL 证书验证(因为使用 IP 地址,证书绑定域名)
439
+ final_options = conn_options.dup
440
+
441
+ Faraday.new(nil, final_options) do |c|
442
+ c.request :multipart
443
+ c.request :url_encoded
444
+ c.response :json, content_type: /\bjson$/
445
+ c.adapter :net_http do |http|
446
+ if host_header
447
+ # DoH 模式:使用 IP 地址,禁用 SSL 证书验证
448
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
449
+ UI.message "DoH 模式:已禁用 SSL 证书验证(实验性功能)"
450
+ else
451
+ # 普通模式:使用默认 SSL 验证
452
+ http.verify_mode = OpenSSL::SSL::VERIFY_PEER
453
+ end
454
+ end
455
+ end
456
+ end
457
+
264
458
  def self.get_type(params)
265
459
  type = params[:ipa].nil? ? "android" : "ios"
266
460
 
@@ -271,10 +465,24 @@ module Fastlane
271
465
  type
272
466
  end
273
467
 
274
- def self.checkPublishStatus(client, api_host, api_key, buildKey)
275
- url ="#{api_host}/buildInfo"
468
+ def self.checkPublishStatus(client, api_host, api_key, buildKey, doh_info = nil)
469
+ # URL 保持使用域名(用于显示)
470
+ url = "#{api_host}/buildInfo"
276
471
  UI.message "checkPublishStatus url: #{url}"
277
- response = client.post "#{api_host}/buildInfo", { :_api_key => api_key, :buildKey => buildKey }
472
+
473
+ # 如果使用 DoH,实际请求时使用 IP 地址,但设置 Host header
474
+ actual_url = api_host
475
+ request_headers = {}
476
+
477
+ if doh_info && doh_info[:ip_address]
478
+ # 实际连接使用 IP 地址
479
+ actual_url = api_host.gsub(doh_info[:domain], doh_info[:ip_address])
480
+ # 设置 Host header 为原始域名
481
+ request_headers["Host"] = doh_info[:domain]
482
+ UI.message "DoH 模式:实际连接使用 IP 地址 #{doh_info[:ip_address]},Host header: #{doh_info[:domain]}"
483
+ end
484
+
485
+ response = client.post "#{actual_url}/buildInfo", { :_api_key => api_key, :buildKey => buildKey }, request_headers
278
486
  info = response.body
279
487
  code = info["code"]
280
488
  if code == 0
@@ -288,7 +496,7 @@ module Fastlane
288
496
  return info["data"]
289
497
  elsif code == 1246 || code == 1247
290
498
  sleep 3
291
- self.checkPublishStatus(client, api_host, api_key, buildKey)
499
+ self.checkPublishStatus(client, api_host, api_key, buildKey, doh_info)
292
500
  else
293
501
  UI.user_error!("PGYER Plugin Published Error: #{info} buildKey: #{buildKey}")
294
502
  end
@@ -1,5 +1,5 @@
1
1
  module Fastlane
2
2
  module Pgyer
3
- VERSION = "0.3.2"
3
+ VERSION = "0.3.3"
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fastlane-plugin-pgyer
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.2
4
+ version: 0.3.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - rexshi
@@ -178,7 +178,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
178
178
  - !ruby/object:Gem::Version
179
179
  version: '0'
180
180
  requirements: []
181
- rubygems_version: 3.7.1
181
+ rubygems_version: 3.6.9
182
182
  specification_version: 4
183
183
  summary: distribute app to pgyer beta testing service
184
184
  test_files: []