fastlane-plugin-pgyer 0.3.2 → 0.4.0

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: 06ca6f9b594d2e759e0f20a9d71b739d879164c2ccbeb48f8e0f04610de958ed
4
+ data.tar.gz: c8e6c3a582a501a90791ed88afc49cda805f906fafe695248ba49b8c75e82154
5
5
  SHA512:
6
- metadata.gz: 5f6df6193af437a950c61ba737e19bee1282b71c0bc2fb8fabfb151c6928bf44ca6d34acf668e4d64a342704aa74f7dce76f0f2d0f60d81c4061473854e3d541
7
- data.tar.gz: f678c0607a076a3df8ba0315316fa0bf8278a4a3b109e1fb448a6298f5b50c4c33a7bb8c9549a01553331cd12c6841748f67dcaf8ac4b13277c26769503eeb3d
6
+ metadata.gz: a73a66059d823f9b265f1d88cac2a57d29b198279691b56a4265523788bb5cd6fad069bbdb52c28ff4dde44166a58fefd3ff85ab320e1dcb1e72417496f93482
7
+ data.tar.gz: 7afc88fa67adf9d5d84f2213c3eeef031386b094cc61a8dd2dc2e1efd5efea7bb7fb04bbcef78d0675f1e607faf834e07f65e048844f8ce0738a3a74ef1c8b99
@@ -1,5 +1,10 @@
1
1
  require "faraday"
2
- require "faraday_middleware"
2
+ if Gem::Version.new(Faraday::VERSION) >= Gem::Version.new("2.0.0")
3
+ require "faraday/multipart"
4
+ else
5
+ require "faraday_middleware"
6
+ end
7
+ require "timeout"
3
8
 
4
9
  module Fastlane
5
10
  module Actions
@@ -74,18 +79,9 @@ module Fastlane
74
79
  },
75
80
  }
76
81
 
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
82
+ # 选择可用的 API 域名
83
+ use_doh = params[:doh] == true
84
+ api_host, pgyer_client, info = self.select_available_api_host(conn_options, request_params, use_doh)
89
85
 
90
86
  if info["code"] != 0
91
87
  UI.user_error!("Get token is failed, info: #{info}")
@@ -121,7 +117,16 @@ module Fastlane
121
117
  UI.user_error!("PGYER Plugin Upload Error: #{response.body}")
122
118
  end
123
119
 
124
- answer = self.checkPublishStatus(pgyer_client, api_host, api_key, key)
120
+ # 如果使用 DoH,需要传递 DoH 相关信息
121
+ doh_info = nil
122
+ if use_doh && api_host.include?("www.pgyer.com")
123
+ domain = "www.pgyer.com"
124
+ ip_address = resolve_domain_via_doh(domain)
125
+ if ip_address
126
+ doh_info = { domain: domain, ip_address: ip_address }
127
+ end
128
+ end
129
+ answer = self.checkPublishStatus(pgyer_client, api_host, api_key, key, doh_info)
125
130
 
126
131
  if params[:save_uploaded_info_json]
127
132
  File.open("pgyer-fastlane-uploaded-app-info.json", "w") do |f|
@@ -181,7 +186,7 @@ module Fastlane
181
186
  end),
182
187
  FastlaneCore::ConfigItem.new(key: :hap,
183
188
  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",
189
+ description: "Path to your HAP file",
185
190
  default_value: Actions.lane_context[:HVIGOR_HAP_OUTPUT_PATH],
186
191
  optional: true,
187
192
  verify_block: proc do |value|
@@ -248,6 +253,12 @@ module Fastlane
248
253
  description: "Need to update the specified channel of the download short link, can specify only one channel, string type, such as: ABCD",
249
254
  optional: true,
250
255
  type: String),
256
+ FastlaneCore::ConfigItem.new(key: :doh,
257
+ env_name: "PGYER_DOH",
258
+ description: "Use DNS over HTTPS (DoH) to resolve domain names, bypassing local DNS. Experimental feature",
259
+ optional: true,
260
+ default_value: false,
261
+ type: Boolean),
251
262
  ]
252
263
  end
253
264
 
@@ -261,6 +272,193 @@ module Fastlane
261
272
 
262
273
  private
263
274
 
275
+ def self.select_available_api_host(conn_options, request_params, use_doh = false)
276
+ # 如果启用 DoH,直接使用 DoH 解析 www.pgyer.com,跳过三个域名测试
277
+ if use_doh
278
+ return select_api_host_via_doh(conn_options, request_params)
279
+ end
280
+
281
+ # 尝试多个域名,防止 DNS 劫持
282
+ api_hosts = [
283
+ "https://www.pgyer.com/apiv2/app",
284
+ "https://www.xcxwo.com/apiv2/app",
285
+ "https://www.pgyerapp.com/apiv2/app",
286
+ ]
287
+
288
+ api_host = nil
289
+ pgyer_client = nil
290
+ info = nil
291
+
292
+ api_hosts.each_with_index do |host, index|
293
+ UI.message "尝试使用域名 #{index + 1}/#{api_hosts.length}: #{host}"
294
+
295
+ begin
296
+ # 为域名检测设置 5 秒超时
297
+ test_conn_options = {
298
+ request: {
299
+ timeout: 5,
300
+ open_timeout: 5,
301
+ },
302
+ }
303
+ test_client = create_faraday_client(test_conn_options, nil)
304
+
305
+ # 使用超时控制,5 秒后如果还没响应就放弃
306
+ test_response = nil
307
+ test_info = nil
308
+
309
+ begin
310
+ Timeout.timeout(5) do
311
+ test_response = test_client.post "#{host}/getCOSToken", request_params
312
+ test_info = test_response.body
313
+ end
314
+ rescue Timeout::Error
315
+ UI.message "域名 #{host} 请求超时(5秒),切换到下一个域名"
316
+ next
317
+ end
318
+
319
+ # 检查响应是否有效:如果返回了有效的 JSON 且包含 code 字段,说明域名解析正常
320
+ if test_info && test_info.is_a?(Hash) && test_info.key?("code")
321
+ if test_info["code"] == 0
322
+ # API 调用成功,使用该域名
323
+ # 使用原始的超时设置重新创建客户端(用于后续上传)
324
+ api_host = host
325
+ pgyer_client = create_faraday_client(conn_options, nil)
326
+ info = test_info
327
+ UI.success "成功使用域名: #{host}"
328
+ break
329
+ else
330
+ # API 返回了业务错误,但域名解析正常
331
+ # 保存第一个可用的域名作为备选,继续尝试其他域名看是否有返回 code == 0 的
332
+ if api_host.nil?
333
+ api_host = host
334
+ # 使用原始的超时设置重新创建客户端
335
+ pgyer_client = create_faraday_client(conn_options, nil)
336
+ info = test_info
337
+ UI.message "域名 #{host} 解析正常,但 API 返回错误,保存为备选: #{test_info}"
338
+ else
339
+ UI.message "域名 #{host} 可用,但 API 返回错误: #{test_info}"
340
+ end
341
+ end
342
+ else
343
+ # 响应格式不正确,可能是 DNS 劫持
344
+ UI.message "域名 #{host} 返回的响应格式不正确,可能遭遇 DNS 劫持"
345
+ end
346
+ rescue => e
347
+ UI.message "域名 #{host} 测试失败(可能是 DNS 劫持或超时): #{e.message}"
348
+ next
349
+ end
350
+ end
351
+
352
+ if api_host.nil? || pgyer_client.nil? || info.nil?
353
+ UI.user_error!("所有域名都无法使用,可能都遭遇了 DNS 劫持。尝试的域名: #{api_hosts.join(', ')}")
354
+ end
355
+
356
+ return api_host, pgyer_client, info
357
+ end
358
+
359
+ # DoH 模式:使用 DoH 解析 www.pgyer.com(实验性功能)
360
+ def self.select_api_host_via_doh(conn_options, request_params)
361
+ UI.message "启用 DoH 模式,使用 DoH 解析 www.pgyer.com"
362
+
363
+ host = "https://www.pgyer.com/apiv2/app"
364
+ domain = "www.pgyer.com"
365
+
366
+ # 通过 DoH 解析域名
367
+ ip_address = resolve_domain_via_doh(domain)
368
+
369
+ if ip_address.nil?
370
+ UI.user_error!("DoH 解析失败,无法获取 www.pgyer.com 的 IP 地址")
371
+ end
372
+
373
+ UI.message "DoH 解析成功: #{domain} -> #{ip_address}"
374
+
375
+ # 使用 IP 地址替换域名,但保留 Host header
376
+ actual_url = host.gsub(domain, ip_address)
377
+ host_header = domain
378
+
379
+ begin
380
+ test_client = create_faraday_client(conn_options, host_header)
381
+
382
+ # 设置 Host header
383
+ request_headers = { "Host" => host_header }
384
+
385
+ test_response = test_client.post "#{actual_url}/getCOSToken", request_params, request_headers
386
+ test_info = test_response.body
387
+
388
+ if test_info && test_info.is_a?(Hash) && test_info.key?("code")
389
+ if test_info["code"] == 0
390
+ UI.success "DoH 模式:成功使用域名 #{host}"
391
+ return host, test_client, test_info
392
+ else
393
+ UI.user_error!("DoH 模式:API 返回错误: #{test_info}")
394
+ end
395
+ else
396
+ UI.user_error!("DoH 模式:返回的响应格式不正确: #{test_info}")
397
+ end
398
+ rescue => e
399
+ UI.user_error!("DoH 模式:请求失败: #{e.message}")
400
+ end
401
+ end
402
+
403
+ # DoH 相关方法(实验性功能)
404
+ def self.resolve_domain_via_doh(domain)
405
+ # 使用阿里云公共 DoH 服务
406
+ doh_url = "https://dns.alidns.com/resolve"
407
+
408
+ begin
409
+ doh_client = Faraday.new do |c|
410
+ c.request :url_encoded
411
+ c.response :json
412
+ c.adapter :net_http
413
+ end
414
+
415
+ response = doh_client.get(doh_url, { name: domain, type: "A" })
416
+ result = response.body
417
+
418
+ if result && result.is_a?(Hash) && result["Answer"]
419
+ # 获取第一个 A 记录
420
+ a_record = result["Answer"].find { |r| r["type"] == 1 }
421
+ if a_record && a_record["data"]
422
+ return a_record["data"]
423
+ end
424
+ end
425
+ rescue => e
426
+ UI.message "DoH 解析出错: #{e.message}"
427
+ end
428
+
429
+ return nil
430
+ end
431
+
432
+ def self.extract_domain_from_url(url)
433
+ # 从 URL 中提取域名
434
+ # 例如: https://www.pgyer.com/apiv2/app -> www.pgyer.com
435
+ uri = URI.parse(url)
436
+ return uri.host
437
+ end
438
+
439
+ def self.create_faraday_client(conn_options, host_header = nil)
440
+ # 创建基础的 Faraday 客户端
441
+ # Host header 将在请求时通过 headers 参数设置
442
+ # DoH 模式下禁用 SSL 证书验证(因为使用 IP 地址,证书绑定域名)
443
+ final_options = conn_options.dup
444
+
445
+ Faraday.new(nil, final_options) do |c|
446
+ c.request :multipart
447
+ c.request :url_encoded
448
+ c.response :json, content_type: /\bjson$/
449
+ c.adapter :net_http do |http|
450
+ if host_header
451
+ # DoH 模式:使用 IP 地址,禁用 SSL 证书验证
452
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
453
+ UI.message "DoH 模式:已禁用 SSL 证书验证(实验性功能)"
454
+ else
455
+ # 普通模式:使用默认 SSL 验证
456
+ http.verify_mode = OpenSSL::SSL::VERIFY_PEER
457
+ end
458
+ end
459
+ end
460
+ end
461
+
264
462
  def self.get_type(params)
265
463
  type = params[:ipa].nil? ? "android" : "ios"
266
464
 
@@ -271,10 +469,24 @@ module Fastlane
271
469
  type
272
470
  end
273
471
 
274
- def self.checkPublishStatus(client, api_host, api_key, buildKey)
275
- url ="#{api_host}/buildInfo"
472
+ def self.checkPublishStatus(client, api_host, api_key, buildKey, doh_info = nil)
473
+ # URL 保持使用域名(用于显示)
474
+ url = "#{api_host}/buildInfo"
276
475
  UI.message "checkPublishStatus url: #{url}"
277
- response = client.post "#{api_host}/buildInfo", { :_api_key => api_key, :buildKey => buildKey }
476
+
477
+ # 如果使用 DoH,实际请求时使用 IP 地址,但设置 Host header
478
+ actual_url = api_host
479
+ request_headers = {}
480
+
481
+ if doh_info && doh_info[:ip_address]
482
+ # 实际连接使用 IP 地址
483
+ actual_url = api_host.gsub(doh_info[:domain], doh_info[:ip_address])
484
+ # 设置 Host header 为原始域名
485
+ request_headers["Host"] = doh_info[:domain]
486
+ UI.message "DoH 模式:实际连接使用 IP 地址 #{doh_info[:ip_address]},Host header: #{doh_info[:domain]}"
487
+ end
488
+
489
+ response = client.post "#{actual_url}/buildInfo", { :_api_key => api_key, :buildKey => buildKey }, request_headers
278
490
  info = response.body
279
491
  code = info["code"]
280
492
  if code == 0
@@ -288,7 +500,7 @@ module Fastlane
288
500
  return info["data"]
289
501
  elsif code == 1246 || code == 1247
290
502
  sleep 3
291
- self.checkPublishStatus(client, api_host, api_key, buildKey)
503
+ self.checkPublishStatus(client, api_host, api_key, buildKey, doh_info)
292
504
  else
293
505
  UI.user_error!("PGYER Plugin Published Error: #{info} buildKey: #{buildKey}")
294
506
  end
@@ -1,5 +1,5 @@
1
1
  module Fastlane
2
2
  module Pgyer
3
- VERSION = "0.3.2"
3
+ VERSION = "0.4.0"
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,14 +1,29 @@
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.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - rexshi
8
+ autorequire:
8
9
  bindir: bin
9
10
  cert_chain: []
10
- date: 1980-01-02 00:00:00.000000000 Z
11
+ date: 2026-08-20 00:00:00.000000000 Z
11
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: faraday-multipart
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.0'
12
27
  - !ruby/object:Gem::Dependency
13
28
  name: bundler
14
29
  requirement: !ruby/object:Gem::Requirement
@@ -149,6 +164,7 @@ dependencies:
149
164
  - - ">="
150
165
  - !ruby/object:Gem::Version
151
166
  version: '0'
167
+ description:
152
168
  email: rexshi@pgyer.com
153
169
  executables: []
154
170
  extensions: []
@@ -164,6 +180,7 @@ homepage: https://github.com/shishirui/fastlane-plugin-pgyer
164
180
  licenses:
165
181
  - MIT
166
182
  metadata: {}
183
+ post_install_message:
167
184
  rdoc_options: []
168
185
  require_paths:
169
186
  - lib
@@ -178,7 +195,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
178
195
  - !ruby/object:Gem::Version
179
196
  version: '0'
180
197
  requirements: []
181
- rubygems_version: 3.7.1
198
+ rubygems_version: 3.0.3.1
199
+ signing_key:
182
200
  specification_version: 4
183
201
  summary: distribute app to pgyer beta testing service
184
202
  test_files: []