cocoapods-privacy 0.2.5 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 17bcbadaa7fac402b93e8895f8122c527873f24c25698809657999163ad7a5b5
4
- data.tar.gz: 511460533641f68349937f6b1bbb90ab65fe51eccc8eb2154eb41926169cf008
3
+ metadata.gz: 6483e616caac6ef86430a25f23bc8f9dd0ea9b61677392d2dbe348170d679d37
4
+ data.tar.gz: 07a796d452a9ad9a6e9e8b0883612c9ec9fb38b40d9dce46a6ecd290026b7a6d
5
5
  SHA512:
6
- metadata.gz: cd028ae88664c51755d97bc79023e2eccf3245646dce468784197284a287ad525195e8a205cab60b8c36d9e46f3f88935627fa84f1e247e96c1efc72d5fa0841
7
- data.tar.gz: a0ba51fe193e4415b1103e03401946acc3db965c594a990a34e1d24927404e583a4557fce182cd62a96f295b7841fc64bd4530572f65ba4d0773a50678540f94
6
+ metadata.gz: a529a41b248f662a4ad21b55a73902875c0b8d530128fe36c472b36888cd511ff5e6a15c7ec1d7a8f8f6f28592dfc3055b8216b8f050c466bc00954973283581
7
+ data.tar.gz: 12c36de4eee58b504c3bd6725ba16cb71db052560882264507289a46381ecf8f980533e10b21582fc9349aa2c709f13cfaed83494c0b887179a596d8c0421b1e
data/README.md CHANGED
@@ -24,6 +24,10 @@ There has 3 keys in defalut config, you should custom it!
24
24
  "source.black.list": ["replace me such as github.com"],
25
25
  "api.template.url": "https://raw.githubusercontent.com/ymoyao/cocoapods-privacy/main/resources/NSPrivacyAccessedAPITypes.plist"
26
26
  ```
27
+ After custom,you can set local config like this
28
+ ```
29
+ $ pod privacy config /yourfilepath/config.json
30
+ ```
27
31
 
28
32
  #### To Component
29
33
  ```
@@ -1,3 +1,3 @@
1
1
  module CocoapodsPrivacy
2
- VERSION = "0.2.5"
2
+ VERSION = "0.3.0"
3
3
  end
@@ -36,12 +36,12 @@ module PrivacyHunter
36
36
  [apis,keyword_type_map]
37
37
  end
38
38
 
39
- def self.search_pricacy_apis(source_folders)
39
+ def self.search_pricacy_apis(source_folders,exclude_folders=[])
40
40
  apis,keyword_type_map = formatter_privacy_template()
41
41
 
42
42
  # 优化写法,一次循环完成所有查询
43
43
  datas = []
44
- apis_found = search_files(source_folders, apis)
44
+ apis_found = search_files(source_folders, exclude_folders, apis)
45
45
  unless apis_found.empty?
46
46
  apis_found.each do |keyword,reason|
47
47
  reasons = reason.split(',')
@@ -197,7 +197,7 @@ module PrivacyHunter
197
197
  end
198
198
 
199
199
  #搜索所有子文件夹
200
- def self.search_files(folder_paths, apis)
200
+ def self.search_files(folder_paths, exclude_folders, apis)
201
201
  # 获取文件夹下所有文件(包括子文件夹)
202
202
  all_files = []
203
203
  folder_paths.each do |folder|
@@ -212,9 +212,20 @@ module PrivacyHunter
212
212
  # 过滤掉目录路径,只保留文件路径,并将其添加到 all_files 数组中
213
213
  all_files += files_in_folder.reject { |file| File.directory?(file) }
214
214
  end
215
+
216
+ # 获取需要排除的文件
217
+ exclude_files = []
218
+ exclude_folders.each do |folder|
219
+ files_in_folder = Dir.glob(folder, File::FNM_DOTMATCH)
220
+ exclude_files += files_in_folder.reject { |file| File.directory?(file) }
221
+ end
222
+
223
+ # 剔除掉需要排除的文件
224
+ all_files = all_files.uniq - exclude_files.uniq
225
+
215
226
  # 遍历文件进行检索
216
227
  apis_found = {}
217
- all_files.uniq.each_with_index do |file_path, index|
228
+ all_files.each_with_index do |file_path, index|
218
229
  api_contains = contains_apis?(file_path, apis)
219
230
  apis_found = apis_found.merge(api_contains)
220
231
 
@@ -3,6 +3,10 @@ require 'cocoapods-core/specification/dsl/attribute_support'
3
3
  require 'cocoapods-core/specification/dsl/attribute'
4
4
  require 'xcodeproj'
5
5
 
6
+ KSource_Files_Key = 'source_files' #不存在单数 source_file
7
+ KExclude_Files_Key = 'exclude_files' #不存在单数 exclude_file
8
+ KResource_Bundle_Key = 'resource_bundle' #resource_bundle 和 resource_bundles 这两个参数本质上是一样的,resource_bundle 也能指向多个参数
9
+
6
10
  class BBRow
7
11
  attr_accessor :content, :is_comment, :is_spec_start, :is_spec_end, :key, :value
8
12
 
@@ -29,11 +33,10 @@ class BBRow
29
33
  end
30
34
 
31
35
  class BBSpec
32
- attr_accessor :name, :alias_name, :full_name, :parent, :rows, :privacy_sources, :privacy_file
36
+ attr_accessor :name, :alias_name, :full_name, :parent, :rows, :privacy_sources_files, :privacy_exclude_files, :privacy_file
33
37
 
34
38
  def initialize(name,alias_name,full_name)
35
39
  @rows = []
36
- @privacy_sources = nil
37
40
  @name = name
38
41
  @alias_name = alias_name
39
42
  @full_name = full_name
@@ -57,103 +60,139 @@ class BBSpec
57
60
  "#{@full_name}.#{name}"
58
61
  end
59
62
 
63
+ # 单独属性转成spec字符串,方便解析
64
+ def assemble_single_property_to_complex(property_name)
65
+ property_name += "s" if property_name == KResource_Bundle_Key #检测到单数resource_bundle,直接转成复数,功能一致
66
+ property_name
67
+ end
68
+
60
69
  def privacy_handle(podspec_file_path)
61
- source_files_index = 1
62
70
  @rows.each_with_index do |line, index|
63
71
  if !line || line.is_a?(BBSpec) || !line.key || line.key.empty?
64
72
  next
65
73
  end
66
74
 
67
- if !line.is_comment && line.key.include?(".resource_bundle")
75
+ if !line.is_comment && line.key.include?("." + KResource_Bundle_Key)
68
76
  @has_resource_bundle = true
69
- elsif !line.is_comment && line.key.include?(".source_files")
70
- begin
71
- code = "Pod::Spec.new do |s|; s.source_files = #{line.value}; end;"
72
- RubyVM::InstructionSequence.compile(code)
73
- spec = eval(code)
74
- rescue SyntaxError, StandardError => e
75
- raise Pod::Informative, "source_files字段 不支持多行拼写,请修改成成单行格式,重新执行pod privacy spec 命令"
76
- end
77
-
78
- if spec && !spec.attributes_hash['source_files'].nil?
79
- source_files_value = spec.attributes_hash['source_files']
80
- if source_files_value.is_a?(String) && !source_files_value.empty?
81
- source_files_array = [source_files_value]
82
- elsif source_files_value.is_a?(Array)
83
- # 如果已经是数组,直接使用
84
- source_files_array = source_files_value
85
- else
86
- # 其他情况,默认为空数组
87
- source_files_array = []
88
- end
89
-
90
- source_files_index = index
91
- @privacy_sources = source_files_array.map do |file_path|
92
- File.join(File.dirname(podspec_file_path), file_path.strip)
93
- end
94
- end
77
+ elsif !line.is_comment && line.key.include?("." + KSource_Files_Key)
78
+ @source_files_index = index
95
79
  end
96
80
  end
97
81
  create_privacy_file_if_need(podspec_file_path)
98
- modify_privacy_resource_bundle_if_need(source_files_index)
82
+ modify_privacy_resource_bundle_if_need(podspec_file_path)
99
83
  end
100
84
 
101
85
  # 对应Spec新增隐私文件
102
86
  def create_privacy_file_if_need(podspec_file_path)
103
- if @privacy_sources
87
+ if @source_files_index
104
88
  PrivacyUtils.create_privacy_if_empty(File.join(File.dirname(podspec_file_path), @privacy_file))
105
89
  end
106
90
  end
107
91
 
108
- # 把新增的隐私文件 映射给 podspec
109
- def modify_privacy_resource_bundle_if_need(source_files_index)
110
- if @privacy_sources
111
- privacy_resource_bundle = { "#{full_name}.privacy" => @privacy_file }
112
- if @has_resource_bundle
113
- line_incomplete = nil
114
- @rows.each_with_index do |line, index|
115
- if !line || line.is_a?(BBSpec)
116
- next
92
+ # 这里处理所有多行参数的解析,目前处理 source_files\exclude_files\resource_bundle 这三种
93
+ # 输入格式 ['.source_files':false,'.exclude_files':true......] => true 代表会根据获取的重置属性,需要把多行多余的进行删除
94
+ # 返回格式 {'.source_files':BBRow,......}
95
+ def fetch_mul_line_property(propertys_mul_line_hash)
96
+ property_hash = {}
97
+ line_processing = nil
98
+ property_config_processing = nil
99
+ @rows.each_with_index do |line, index|
100
+ if !line || line.is_a?(BBSpec) || line.is_comment
101
+ next
102
+ end
103
+
104
+ property_find = propertys_mul_line_hash.find { |key, _| line.key && line.key.include?(key) } #查找不到返回nil 查到返回数组,key, value 分别在第一和第二个参数
105
+ if property_find
106
+ property_config_processing = property_find
107
+ end
108
+
109
+ if property_config_processing
110
+ begin
111
+ property_name = property_config_processing.first
112
+ is_replace_line = property_config_processing.second
113
+ if line_processing
114
+ code = "#{line_processing.value}#{line.content}"
115
+ else
116
+ code = "#{line.value}"
117
117
  end
118
118
 
119
- is_resource_bundle_line = line.key && line.key.include?(".resource_bundle")
120
- if !line.is_comment && (is_resource_bundle_line || line_incomplete)
121
- begin
122
- if line_incomplete
123
- code = "#{line_incomplete.value}#{line.content}"
124
- else
125
- code = "#{line.value}"
126
- end
127
-
128
- # 清除 content 和 value, 后面会把所有的resource_bundle 组装起来,多余的内容要清除,避免重复
129
- line.content = ''
130
- line.value = nil
131
-
132
- RubyVM::InstructionSequence.compile(code)
133
- origin_resource_bundle = eval(code)
134
- rescue SyntaxError, StandardError => e
135
- unless line_incomplete
136
- line_incomplete = line
137
- end
138
- line_incomplete.value = code if line_incomplete #存储当前残缺的value,和后面完整的进行拼接
139
- next
140
- end
141
-
142
- final_line = (line_incomplete ? line_incomplete : line)
143
-
144
- merged_resource_bundle = origin_resource_bundle.merge(privacy_resource_bundle)
145
- @resource_bundle = merged_resource_bundle
146
- final_line.value = merged_resource_bundle
147
- final_line.content = "#{final_line.key}= #{final_line.value}"
148
- break
119
+ # 清除 content value, 后面会把所有的content 组装起来,多余的内容要清除,避免重复
120
+ if is_replace_line
121
+ line.content = ''
122
+ line.value = nil
149
123
  end
124
+
125
+ property_name_complex = assemble_single_property_to_complex(property_name)
126
+ spec_str = "Pod::Spec.new do |s|; s.#{property_name_complex} = #{code}; end;"
127
+ RubyVM::InstructionSequence.compile(spec_str)
128
+ spec = eval(spec_str)
129
+ property_value = spec.attributes_hash[property_name_complex]
130
+ rescue SyntaxError, StandardError => e
131
+ unless line_processing
132
+ line_processing = line
133
+ end
134
+ line_processing.value = code if line_processing #存储当前残缺的value,和后面完整的进行拼接
135
+ next
150
136
  end
151
- else
152
- space = PrivacyUtils.count_spaces_before_first_character(rows[source_files_index].content)
137
+
138
+ final_line = (line_processing ? line_processing : line)
139
+ final_line.value = property_value
140
+ property_hash[property_name] = final_line
141
+ line_processing = nil
142
+ property_config_processing = nil
143
+ end
144
+ end
145
+
146
+ property_hash
147
+ end
148
+
149
+ # 处理字符串或者数组,使其全都转为数组,并转成实际文件夹地址
150
+ def handle_string_or_array_files(podspec_file_path,line)
151
+ value = line.value
152
+ if value.is_a?(String) && !value.empty?
153
+ array = [value]
154
+ elsif value.is_a?(Array)
155
+ array = value
156
+ else
157
+ array = []
158
+ end
159
+
160
+ files = array.map do |file_path|
161
+ File.join(File.dirname(podspec_file_path), file_path.strip)
162
+ end
163
+ files
164
+ end
165
+
166
+ # 把新增的隐私文件 映射给 podspec && 解析 privacy_sources_files && 解析 privacy_exclude_files
167
+ def modify_privacy_resource_bundle_if_need(podspec_file_path)
168
+ if @source_files_index
169
+ privacy_resource_bundle = { "#{full_name}.privacy" => @privacy_file }
170
+
171
+ # 这里处理所有多行参数的解析,目前处理 source_files\exclude_files\resource_bundle 这三种
172
+ propertys_mul_line_hash = {}
173
+ propertys_mul_line_hash[KSource_Files_Key] = false
174
+ propertys_mul_line_hash[KExclude_Files_Key] = false
175
+ if @has_resource_bundle
176
+ propertys_mul_line_hash[KResource_Bundle_Key] = true #需要根据生成的重置属性
177
+ else # 如果原先没有resource_bundle,需要单独加一行resource_bundle
178
+ space = PrivacyUtils.count_spaces_before_first_character(rows[@source_files_index].content)
153
179
  line = "#{alias_name}.resource_bundle = #{privacy_resource_bundle}"
154
180
  line = PrivacyUtils.add_spaces_to_string(line,space)
155
181
  row = BBRow.new(line)
156
- @rows.insert(source_files_index+1, row)
182
+ @rows.insert(@source_files_index+1, row)
183
+ end
184
+ property_value_hash = fetch_mul_line_property(propertys_mul_line_hash)
185
+ property_value_hash.each do |property, line|
186
+ if property == KSource_Files_Key #处理 source_files
187
+ @privacy_sources_files = handle_string_or_array_files(podspec_file_path,line)
188
+ elsif property == KExclude_Files_Key #处理 exclude_files
189
+ @privacy_exclude_files = handle_string_or_array_files(podspec_file_path,line)
190
+ elsif property == KResource_Bundle_Key #处理 原有resource_bundle 合并隐私清单文件映射
191
+ merged_resource_bundle = line.value.merge(privacy_resource_bundle)
192
+ @resource_bundle = merged_resource_bundle
193
+ line.value = merged_resource_bundle
194
+ line.content = "#{line.key}= #{line.value}"
195
+ end
157
196
  end
158
197
  end
159
198
  end
@@ -165,7 +204,7 @@ module PrivacyModule
165
204
  public
166
205
 
167
206
  # 处理工程
168
- def self.load_project(folds)
207
+ def self.load_project(folds,exclude_folds)
169
208
  project_path = PrivacyUtils.project_path()
170
209
  resources_folder_path = File.join(File.basename(project_path, File.extname(project_path)),'Resources')
171
210
  privacy_file_path = File.join(resources_folder_path,PrivacyUtils.privacy_name)
@@ -198,7 +237,7 @@ module PrivacyModule
198
237
 
199
238
  # 开始检索api,并返回json 字符串数据
200
239
  PrivacyLog.clean_result_log()
201
- json_data = PrivacyHunter.search_pricacy_apis(folds)
240
+ json_data = PrivacyHunter.search_pricacy_apis(folds,exclude_folds)
202
241
 
203
242
  # 将数据写入隐私清单文件
204
243
  PrivacyHunter.write_to_privacy(json_data,privacy_file_path)
@@ -210,9 +249,11 @@ module PrivacyModule
210
249
  puts "👇👇👇👇👇👇 Start analysis component privacy 👇👇👇👇👇👇"
211
250
  PrivacyLog.clean_result_log()
212
251
  privacy_hash = PrivacyModule.check(podspec_file_path)
213
- privacy_hash.each do |privacy_file_path, source_files|
252
+ privacy_hash.each do |privacy_file_path, hash|
214
253
  PrivacyLog.write_to_result_log("#{privacy_file_path}: \n")
215
- data = PrivacyHunter.search_pricacy_apis(source_files)
254
+ source_files = hash[KSource_Files_Key]
255
+ exclude_files = hash[KExclude_Files_Key]
256
+ data = PrivacyHunter.search_pricacy_apis(source_files,exclude_files)
216
257
  PrivacyHunter.write_to_privacy(data,privacy_file_path) unless data.empty?
217
258
  end
218
259
  PrivacyLog.result_log_tip()
@@ -353,9 +394,10 @@ module PrivacyModule
353
394
 
354
395
  def self.fetch_privacy_hash(rows,podspec_file_path)
355
396
  privacy_hash = {}
356
- filtered_rows = rows.select { |row| row.is_a?(BBSpec) }
357
- filtered_rows.each do |spec|
358
- privacy_hash[File.join(File.dirname(podspec_file_path),spec.privacy_file)] = spec.privacy_sources
397
+ specs = rows.select { |row| row.is_a?(BBSpec) }
398
+ specs.each do |spec|
399
+ value = spec.privacy_sources_files ? {KSource_Files_Key => spec.privacy_sources_files,KExclude_Files_Key => spec.privacy_exclude_files || []} : {}
400
+ privacy_hash[File.join(File.dirname(podspec_file_path),spec.privacy_file)] = value
359
401
  privacy_hash.merge!(fetch_privacy_hash(spec.rows,podspec_file_path))
360
402
  end
361
403
  privacy_hash
@@ -83,16 +83,19 @@ module Pod
83
83
 
84
84
  # 存储本地调试组件
85
85
  development_folds = []
86
+ exclude_folds = []
86
87
 
87
88
  # 获取组件所在工程的pods 目录
88
89
  pod_folds = modules.map{ |spec|
89
90
  name = spec.name.split('/').first
91
+
90
92
  fold = File.join(@sandbox.root,name)
91
93
  podspec_file_path_develop = validate_development_pods(name)
92
94
  # 先验证是否是指向本地的组件(发现有的情况下 组件指向本地Pods 下依旧还是会有该组件,所以这里先判断本地的)
93
95
  if podspec_file_path_develop
94
96
  podspec_fold_path = File.dirname(podspec_file_path_develop)
95
97
  source_files = spec.attributes_hash['source_files']
98
+ exclude_files = spec.attributes_hash['exclude_files']
96
99
  if source_files && !source_files.empty?
97
100
  if source_files.is_a?(String) && !source_files.empty?
98
101
  development_folds << File.join(podspec_fold_path,source_files)
@@ -101,6 +104,17 @@ module Pod
101
104
  development_folds << File.join(podspec_fold_path,file)
102
105
  end
103
106
  end
107
+
108
+ # 处理exclude_files 排除文件夹
109
+ if exclude_files && !exclude_files.empty?
110
+ if exclude_files.is_a?(String) && !exclude_files.empty?
111
+ exclude_folds << File.join(podspec_fold_path,exclude_files)
112
+ elsif exclude_files.is_a?(Array)
113
+ exclude_files.each do |file|
114
+ exclude_folds << File.join(podspec_fold_path,file)
115
+ end
116
+ end
117
+ end
104
118
  end
105
119
  nil
106
120
  elsif Dir.exist?(fold)
@@ -118,7 +132,7 @@ module Pod
118
132
  puts "无组件或工程目录, 请检查工程"
119
133
  else
120
134
  # 处理工程隐私协议
121
- PrivacyModule.load_project(pod_folds)
135
+ PrivacyModule.load_project(pod_folds,exclude_folds.uniq)
122
136
  end
123
137
  puts "👆👆👆👆👆👆 End analysis project privacy 👆👆👆👆👆👆"
124
138
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cocoapods-privacy
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.5
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - youhui
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-02-18 00:00:00.000000000 Z
11
+ date: 2024-03-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler