cocoapods-privacy 0.2.4 → 0.3.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:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6483e616caac6ef86430a25f23bc8f9dd0ea9b61677392d2dbe348170d679d37
|
4
|
+
data.tar.gz: 07a796d452a9ad9a6e9e8b0883612c9ec9fb38b40d9dce46a6ecd290026b7a6d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
```
|
@@ -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.
|
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, :
|
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,96 +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?(".
|
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?(".
|
70
|
-
|
71
|
-
if spec && !spec.attributes_hash['source_files'].nil?
|
72
|
-
source_files_value = spec.attributes_hash['source_files']
|
73
|
-
if source_files_value.is_a?(String) && !source_files_value.empty?
|
74
|
-
source_files_array = [source_files_value]
|
75
|
-
elsif source_files_value.is_a?(Array)
|
76
|
-
# 如果已经是数组,直接使用
|
77
|
-
source_files_array = source_files_value
|
78
|
-
else
|
79
|
-
# 其他情况,默认为空数组
|
80
|
-
source_files_array = []
|
81
|
-
end
|
82
|
-
|
83
|
-
source_files_index = index
|
84
|
-
@privacy_sources = source_files_array.map do |file_path|
|
85
|
-
File.join(File.dirname(podspec_file_path), file_path.strip)
|
86
|
-
end
|
87
|
-
end
|
77
|
+
elsif !line.is_comment && line.key.include?("." + KSource_Files_Key)
|
78
|
+
@source_files_index = index
|
88
79
|
end
|
89
80
|
end
|
90
81
|
create_privacy_file_if_need(podspec_file_path)
|
91
|
-
modify_privacy_resource_bundle_if_need(
|
82
|
+
modify_privacy_resource_bundle_if_need(podspec_file_path)
|
92
83
|
end
|
93
84
|
|
94
85
|
# 对应Spec新增隐私文件
|
95
86
|
def create_privacy_file_if_need(podspec_file_path)
|
96
|
-
if @
|
87
|
+
if @source_files_index
|
97
88
|
PrivacyUtils.create_privacy_if_empty(File.join(File.dirname(podspec_file_path), @privacy_file))
|
98
89
|
end
|
99
90
|
end
|
100
91
|
|
101
|
-
#
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
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
|
+
end
|
118
|
+
|
119
|
+
# 清除 content 和 value, 后面会把所有的content 组装起来,多余的内容要清除,避免重复
|
120
|
+
if is_replace_line
|
121
|
+
line.content = ''
|
122
|
+
line.value = nil
|
110
123
|
end
|
111
124
|
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
# 清除 content 和 value, 后面会把所有的resource_bundle 组装起来,多余的内容要清除,避免重复
|
122
|
-
line.content = ''
|
123
|
-
line.value = nil
|
124
|
-
|
125
|
-
RubyVM::InstructionSequence.compile(code)
|
126
|
-
origin_resource_bundle = eval(code)
|
127
|
-
rescue SyntaxError, StandardError => e
|
128
|
-
unless line_incomplete
|
129
|
-
line_incomplete = line
|
130
|
-
end
|
131
|
-
line_incomplete.value = code if line_incomplete #存储当前残缺的value,和后面完整的进行拼接
|
132
|
-
next
|
133
|
-
end
|
134
|
-
|
135
|
-
final_line = (line_incomplete ? line_incomplete : line)
|
136
|
-
|
137
|
-
merged_resource_bundle = origin_resource_bundle.merge(privacy_resource_bundle)
|
138
|
-
@resource_bundle = merged_resource_bundle
|
139
|
-
final_line.value = merged_resource_bundle
|
140
|
-
final_line.content = "#{final_line.key}= #{final_line.value}"
|
141
|
-
break
|
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
|
142
133
|
end
|
134
|
+
line_processing.value = code if line_processing #存储当前残缺的value,和后面完整的进行拼接
|
135
|
+
next
|
143
136
|
end
|
144
|
-
|
145
|
-
|
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)
|
146
179
|
line = "#{alias_name}.resource_bundle = #{privacy_resource_bundle}"
|
147
180
|
line = PrivacyUtils.add_spaces_to_string(line,space)
|
148
181
|
row = BBRow.new(line)
|
149
|
-
@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
|
150
196
|
end
|
151
197
|
end
|
152
198
|
end
|
@@ -158,7 +204,7 @@ module PrivacyModule
|
|
158
204
|
public
|
159
205
|
|
160
206
|
# 处理工程
|
161
|
-
def self.load_project(folds)
|
207
|
+
def self.load_project(folds,exclude_folds)
|
162
208
|
project_path = PrivacyUtils.project_path()
|
163
209
|
resources_folder_path = File.join(File.basename(project_path, File.extname(project_path)),'Resources')
|
164
210
|
privacy_file_path = File.join(resources_folder_path,PrivacyUtils.privacy_name)
|
@@ -191,7 +237,7 @@ module PrivacyModule
|
|
191
237
|
|
192
238
|
# 开始检索api,并返回json 字符串数据
|
193
239
|
PrivacyLog.clean_result_log()
|
194
|
-
json_data = PrivacyHunter.search_pricacy_apis(folds)
|
240
|
+
json_data = PrivacyHunter.search_pricacy_apis(folds,exclude_folds)
|
195
241
|
|
196
242
|
# 将数据写入隐私清单文件
|
197
243
|
PrivacyHunter.write_to_privacy(json_data,privacy_file_path)
|
@@ -203,9 +249,11 @@ module PrivacyModule
|
|
203
249
|
puts "👇👇👇👇👇👇 Start analysis component privacy 👇👇👇👇👇👇"
|
204
250
|
PrivacyLog.clean_result_log()
|
205
251
|
privacy_hash = PrivacyModule.check(podspec_file_path)
|
206
|
-
privacy_hash.each do |privacy_file_path,
|
252
|
+
privacy_hash.each do |privacy_file_path, hash|
|
207
253
|
PrivacyLog.write_to_result_log("#{privacy_file_path}: \n")
|
208
|
-
|
254
|
+
source_files = hash[KSource_Files_Key]
|
255
|
+
exclude_files = hash[KExclude_Files_Key]
|
256
|
+
data = PrivacyHunter.search_pricacy_apis(source_files,exclude_files)
|
209
257
|
PrivacyHunter.write_to_privacy(data,privacy_file_path) unless data.empty?
|
210
258
|
end
|
211
259
|
PrivacyLog.result_log_tip()
|
@@ -346,9 +394,10 @@ module PrivacyModule
|
|
346
394
|
|
347
395
|
def self.fetch_privacy_hash(rows,podspec_file_path)
|
348
396
|
privacy_hash = {}
|
349
|
-
|
350
|
-
|
351
|
-
|
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
|
352
401
|
privacy_hash.merge!(fetch_privacy_hash(spec.rows,podspec_file_path))
|
353
402
|
end
|
354
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.
|
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-
|
11
|
+
date: 2024-03-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|