cocoapods-privacy 0.5.3 → 0.6.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 +4 -4
- data/README.md +7 -1
- data/lib/cocoapods-privacy/command/confuse/spec.rb +34 -0
- data/lib/cocoapods-privacy/command/install.rb +38 -5
- data/lib/cocoapods-privacy/command/privacy/config.rb +2 -2
- data/lib/cocoapods-privacy/command.rb +17 -2
- data/lib/cocoapods-privacy/common/BBSpec.rb +234 -0
- data/lib/cocoapods-privacy/common/BBSpecManager.rb +166 -0
- data/lib/cocoapods-privacy/common/config.rb +69 -0
- data/lib/cocoapods-privacy/confuse/ConfuseHunter.rb +506 -0
- data/lib/cocoapods-privacy/confuse/ConfuseModule.rb +150 -0
- data/lib/cocoapods-privacy/confuse/ConfuseUtils.rb +107 -0
- data/lib/cocoapods-privacy/confuse/ObjCMethodAPIConverter.rb +194 -0
- data/lib/cocoapods-privacy/confuse/SwiftCallAssembly.rb +24 -0
- data/lib/cocoapods-privacy/confuse/confuse_installer_hook.rb +290 -0
- data/lib/cocoapods-privacy/confuse/confuse_specification_hook.rb +56 -0
- data/lib/cocoapods-privacy/gem_version.rb +1 -1
- data/lib/cocoapods-privacy/privacy/PrivacyHunter.rb +1 -1
- data/lib/cocoapods-privacy/privacy/PrivacyModule.rb +2 -338
- data/lib/cocoapods-privacy/privacy/PrivacyUtils.rb +5 -13
- data/lib/cocoapods-privacy/privacy/privacy_installer_hook.rb +0 -1
- data/lib/cocoapods-privacy/privacy/privacy_specification_hook.rb +4 -1
- metadata +14 -4
- data/lib/cocoapods-privacy/privacy/PrivacyConfig.rb +0 -28
@@ -0,0 +1,506 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'cocoapods-privacy/command'
|
3
|
+
require 'securerandom'
|
4
|
+
require 'active_support/core_ext/module/attribute_accessors'
|
5
|
+
|
6
|
+
##
|
7
|
+
# 功能介绍:
|
8
|
+
# 1、检索到的混淆内容转换成加密议格式写入 混淆文件
|
9
|
+
##
|
10
|
+
module Confuse
|
11
|
+
class Hunter
|
12
|
+
|
13
|
+
# 类变量,用于缓存版本号
|
14
|
+
def initialize(version)
|
15
|
+
@version = version
|
16
|
+
end
|
17
|
+
|
18
|
+
def search_need_confuse_apis(source_folders,exclude_folders=[])
|
19
|
+
apis_define_map, swift_extension_funcBody_map = search_files(source_folders, exclude_folders)
|
20
|
+
return apis_define_map, swift_extension_funcBody_map
|
21
|
+
end
|
22
|
+
|
23
|
+
def insert_encrypted_apis_to_confuse_header(apis_define_map,confuse_header_path,flag = "")
|
24
|
+
# 存储已生成的随机字符串以确保唯一性
|
25
|
+
generated_strings = {}
|
26
|
+
|
27
|
+
# 生成 #define 语句
|
28
|
+
defines = apis_define_map.map { |key, value|
|
29
|
+
" #define #{key} #{value}"
|
30
|
+
}.join("\n")
|
31
|
+
|
32
|
+
confuse_header_content = ConfuseUtils.confuse_content(defines,File.basename(confuse_header_path))
|
33
|
+
puts "混淆(宏):\n 文件:#{confuse_header_path}\n 内容👇:\n#{confuse_header_content}"
|
34
|
+
|
35
|
+
# 保存文件
|
36
|
+
File.write(confuse_header_path, confuse_header_content)
|
37
|
+
end
|
38
|
+
|
39
|
+
def insert_encrypted_apis_to_confuse_swift(swift_extension_funcBody_map,swift_confuse_file_path,flag = "")
|
40
|
+
# 存储已生成的随机字符串以确保唯一性
|
41
|
+
generated_strings = {}
|
42
|
+
|
43
|
+
# 生成 #define 语句
|
44
|
+
funcs = swift_extension_funcBody_map.map { |key, values|
|
45
|
+
func = "public extension #{key} {\n" + values.map { |value|
|
46
|
+
value.split("\n").map { |line| " #{line}" }.join("\n") # 每行前加四个空格
|
47
|
+
}.join("\n\n") + "\n}"
|
48
|
+
}.join("\n")
|
49
|
+
confuse_func_content = funcs
|
50
|
+
puts "混淆(扩展):\n 文件:#{swift_confuse_file_path}\n 内容👇:\n#{confuse_func_content}"
|
51
|
+
|
52
|
+
# # 保存文件
|
53
|
+
File.write(swift_confuse_file_path, confuse_func_content)
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
# # 获取podspec的版本号,如果有缓存则返回缓存值
|
59
|
+
# def self.get_version(podspec_file_path)
|
60
|
+
# # 如果已经缓存了版本号,直接返回缓存
|
61
|
+
# return @cached_version if @cached_version
|
62
|
+
|
63
|
+
# # 读取podspec文件
|
64
|
+
# podspec = Pod::Specification.from_file(podspec_file_path)
|
65
|
+
# version = podspec.version.to_s
|
66
|
+
# version = version.gsub('.', '_') # Replace dots with underscores
|
67
|
+
|
68
|
+
# # 缓存版本号
|
69
|
+
# @cached_version = version
|
70
|
+
|
71
|
+
# return version
|
72
|
+
# end
|
73
|
+
|
74
|
+
def extend_version(str)
|
75
|
+
return "#{str}_V#{@version}"
|
76
|
+
end
|
77
|
+
|
78
|
+
#💡💡💡以下是 invalid byte sequence in UTF-8 错误复现 的数据代码
|
79
|
+
# File.write("/Users/xxx/.cache/cocoapods-privacy/privacy/file.txt", "vandflyver \xC5rhus \n
|
80
|
+
|
81
|
+
# \n
|
82
|
+
|
83
|
+
# \\n
|
84
|
+
|
85
|
+
# vandflyver
|
86
|
+
# \xC5rhus
|
87
|
+
# ")
|
88
|
+
# 文件是否包含内容
|
89
|
+
def extract_annotated_attributes?(file_path)
|
90
|
+
|
91
|
+
#使用UTF-8 读取,无法读取的会被默认处理,修复 https://github.com/ymoyao/cocoapods-privacy/issues/7
|
92
|
+
file_content = File.read(file_path, encoding: 'UTF-8', invalid: :replace, undef: :replace)
|
93
|
+
|
94
|
+
#核心文件检查段落注释 /* */
|
95
|
+
file_extension = File.extname(file_path).downcase
|
96
|
+
need_check_paragraph_comment = ['.m', '.c', '.swift', '.mm', '.h', '.hap', '.hpp', '.cpp'].include?(file_extension)
|
97
|
+
|
98
|
+
apis_define_map, swift_extension_funcBody_map = contains_apis_ignore_all_comment(file_content.lines,file_path)
|
99
|
+
return apis_define_map, swift_extension_funcBody_map
|
100
|
+
end
|
101
|
+
|
102
|
+
def contains_apis_ignore_all_comment(lines,file_path)
|
103
|
+
apis_define_map = {}
|
104
|
+
swift_extension_funcBody_map = {}
|
105
|
+
|
106
|
+
#oc 暴露给swift 的扩展名称
|
107
|
+
swift_extension = ""
|
108
|
+
|
109
|
+
# 段注释和单行注释标志
|
110
|
+
in_block_comment = false
|
111
|
+
in_line_comment = false
|
112
|
+
|
113
|
+
# 是否可以触发注释标识,当为true 时可以触发 /*段注释 或者 //单行注释
|
114
|
+
can_trigger_comments_flag = true
|
115
|
+
|
116
|
+
# 统计计数器
|
117
|
+
count_comments = 0
|
118
|
+
modified = false
|
119
|
+
|
120
|
+
last_line_scrub = ""
|
121
|
+
need_delete_line_map = {} #{删除行下标:行内容line}
|
122
|
+
encrypted_lines = lines.map.with_index do |line, line_index|
|
123
|
+
|
124
|
+
line_scrub = line.scrub("")
|
125
|
+
if line_scrub.strip.empty? #忽略空行
|
126
|
+
next line
|
127
|
+
end
|
128
|
+
if line_scrub.strip.start_with?('//') && !in_block_comment #忽略注释 // 和 /**/
|
129
|
+
next line
|
130
|
+
end
|
131
|
+
|
132
|
+
chars = line_scrub.chars
|
133
|
+
index = 0
|
134
|
+
while index < chars.size
|
135
|
+
char = chars[index]
|
136
|
+
|
137
|
+
if char == '/'
|
138
|
+
if chars[index + 1] == '*'
|
139
|
+
# 检测到 /* 且can_trigger_comments_flag标识为true时,判定为进入 段注释
|
140
|
+
if can_trigger_comments_flag
|
141
|
+
in_line_comment = false #重置行标识
|
142
|
+
in_block_comment = true #标记正在段注释中
|
143
|
+
can_trigger_comments_flag = false #回收头部重置标识
|
144
|
+
end
|
145
|
+
|
146
|
+
#段注释每次 遇到 /* 都累加1
|
147
|
+
if in_block_comment
|
148
|
+
count_comments += 1
|
149
|
+
end
|
150
|
+
|
151
|
+
#跳过当前 /* 两个字符
|
152
|
+
index += 2
|
153
|
+
next
|
154
|
+
end
|
155
|
+
# 检测到段注释的end 标识 */
|
156
|
+
elsif in_block_comment && char == '*' && chars[index + 1] == '/'
|
157
|
+
|
158
|
+
#段注释每次 遇到 */ 都累减1
|
159
|
+
count_comments -= 1
|
160
|
+
|
161
|
+
#当/* */ 配对时,说明当前段注释结束了
|
162
|
+
if count_comments == 0
|
163
|
+
in_line_comment = false
|
164
|
+
in_block_comment = false
|
165
|
+
can_trigger_comments_flag = true
|
166
|
+
end
|
167
|
+
|
168
|
+
#跳过当前 */ 两个字符
|
169
|
+
index += 2
|
170
|
+
next
|
171
|
+
end
|
172
|
+
|
173
|
+
# 其他情况,前进一个字符
|
174
|
+
index += 1
|
175
|
+
end
|
176
|
+
|
177
|
+
if !in_block_comment && !in_line_comment
|
178
|
+
|
179
|
+
###----- 处理oc ------
|
180
|
+
# 查找并处理注解:__attribute__((annotate("BB_?Confuse:xxx")))
|
181
|
+
#.*?: 匹配任意字符(包括冒号),但它会尽量少匹配直到遇到冒号为止。
|
182
|
+
#.*? 匹配冒号后面的一些字符(任意字符,直到遇到下一个双引号)。
|
183
|
+
#这样可以确保匹配的字符串中至少包含一个冒号。
|
184
|
+
line_scrub.scan(/__attribute__\(\(annotate\("(.*?:.*?)"\)\)\)/) do |match|
|
185
|
+
# # 将注解内容按逗号分割功能,并去重
|
186
|
+
commands = match.first.split(',').map(&:strip)
|
187
|
+
commands.map do |commandInfo|
|
188
|
+
puts commandInfo
|
189
|
+
commandKeyAndValue = commandInfo.split(':')
|
190
|
+
commandKey = commandKeyAndValue.first
|
191
|
+
commandValue = commandKeyAndValue.last
|
192
|
+
if commandKey && commandKey =~ /BB_?Confuse/
|
193
|
+
swift_extension = commandValue
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
# new_parts = encrypted_api(apis)
|
198
|
+
|
199
|
+
# apis.each_with_index do |seg, index|
|
200
|
+
# apis_define_map[seg.strip] = new_parts[index]
|
201
|
+
# end
|
202
|
+
|
203
|
+
# puts "__attribute__ = #{match}"
|
204
|
+
end
|
205
|
+
|
206
|
+
# 查找并处理注解:__attribute__((annotate("xxx")))
|
207
|
+
# @regex = /^[+-]\s*\(\s*([^$]+)\s*\**\s*\)\s*(.+)/
|
208
|
+
line_scrub.scan(/(^[-+]\s*\(.*?\)\s*(\w+)\s*([\w\s]+))\s*__attribute__\(\(annotate\(/) do |match|
|
209
|
+
apis = [match.second]
|
210
|
+
new_parts = encrypted_api(apis)
|
211
|
+
|
212
|
+
funcStr = match.first.sub(';','').sub(/__attribute__\(\(annotate\(["][^"]*["]\)\)\).*/, '')
|
213
|
+
swift_method_declaration,params = ObjCMethodAPIConverter.convert(funcStr)
|
214
|
+
if !swift_extension.empty? && swift_method_declaration && !swift_method_declaration.empty?
|
215
|
+
swift_func_body = SwiftCallAssembly.assembly(new_parts.first,swift_method_declaration,params)
|
216
|
+
swift_extension_funcBody_map[swift_extension] ||= []
|
217
|
+
swift_extension_funcBody_map[swift_extension].push(swift_func_body)
|
218
|
+
end
|
219
|
+
apis.each_with_index do |seg, index|
|
220
|
+
apis_define_map[seg.strip] = new_parts[index]
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
###----- 处理swift 类 ------
|
225
|
+
#正则解析:
|
226
|
+
#1、@BBConfuseMixObjcClass\(" 匹配 @BBConfuseMixObjcClass(" 这一部分 @BBConfuseMixObjcClass("MyClass"
|
227
|
+
#2、([a-zA-Z][a-zA-Z0-9]*) 第一个参数:匹配 " 之后的 首字母必须是字母,后面可跟 字母或数字 "MyClass"
|
228
|
+
#3、(?:,\s*"([a-zA-Z][a-zA-Z0-9]*)")? 第二个参数(可选):如果有,匹配 , "SecondParam" , "SecondParam"(可选)
|
229
|
+
#4、\) 匹配 ") 结束 @BBConfuseMixObjcClass(...) 部分 ")
|
230
|
+
#5、(?:.*?@objc\((\S+)\))? 可选的 @objc(...):如果存在,则匹配 @objc(...) 并提取内容 @objc(MyObjCName)(可选)
|
231
|
+
#6、.*?class ([a-zA-Z0-9]+) 类名:匹配 class 关键字后面的类名 class MyClass
|
232
|
+
#混淆之前的类解析(存在 @objc(xxx) 别名情况 ) 比如 @BBConfuseMixObjcClass("test") @objc(xxxx) public class abc : NSObject {
|
233
|
+
confuse_class_pre_literal = "@BBConfuseMixObjcClass"
|
234
|
+
line_scrub.gsub!(/#{confuse_class_pre_literal}\("([a-zA-Z][a-zA-Z0-9]*)"(?:,\s*"([a-zA-Z][a-zA-Z0-9]*)")?\)(?:.*?@objc\((\S+)\))?.*?class ([a-zA-Z0-9]+)/) do |match|
|
235
|
+
#match = @BBConfuseMixObjcClass("test") @objc(xxxx) public class abc
|
236
|
+
#S1 = test
|
237
|
+
#S2 = xxxx
|
238
|
+
#S3 = abc
|
239
|
+
modified = true
|
240
|
+
# puts "检测到混淆类标记 = #{match}"
|
241
|
+
# puts "$1 = #{$1} $2 = #{$2} $3 = #{$3} $4 = #{$4}"
|
242
|
+
origin_swift_class_name = $1
|
243
|
+
origin_objc_class_name = $2 || ""
|
244
|
+
current_objc_class_name = $3 || ""
|
245
|
+
current_swift_class_name = $4
|
246
|
+
is_to_objc = match.include?("@objc")
|
247
|
+
|
248
|
+
encrypted_class_name = encrypted_api([origin_swift_class_name]).first
|
249
|
+
confuse_literals = "#{confuse_class_pre_literal}"
|
250
|
+
unless origin_objc_class_name.empty?
|
251
|
+
confuse_literals += "(\"#{origin_swift_class_name}\",\"#{origin_objc_class_name}\")"
|
252
|
+
else
|
253
|
+
confuse_literals += "(\"#{origin_swift_class_name}\")"
|
254
|
+
end
|
255
|
+
|
256
|
+
class_literals = match
|
257
|
+
.gsub(confuse_literals, "")
|
258
|
+
.gsub(/@objc\([^)]*\)|@objc\s+/, "")
|
259
|
+
.gsub(current_swift_class_name, encrypted_class_name)
|
260
|
+
|
261
|
+
#检查上一行是否已经有public typealias origin_class_name = encrypted_class_name, 有的话先标记删除
|
262
|
+
swift_typealias = "public typealias #{origin_swift_class_name}"
|
263
|
+
if last_line_scrub.delete(" ").include?(swift_typealias.delete(" "))
|
264
|
+
need_delete_line_map[line_index - 1] = last_line_scrub
|
265
|
+
end
|
266
|
+
|
267
|
+
#有包含@objc 暴露给oc 才有宏定义的必要
|
268
|
+
if is_to_objc
|
269
|
+
#添加origin_class_name 和 encrypted_class_name 给字典, 后续插入到宏定义中
|
270
|
+
apis_define_map[origin_swift_class_name] = encrypted_class_name unless origin_swift_class_name.empty?
|
271
|
+
apis_define_map[origin_objc_class_name] = encrypted_class_name unless origin_objc_class_name.empty?
|
272
|
+
end
|
273
|
+
|
274
|
+
objc_literals = is_to_objc ? " @objc(#{encrypted_class_name.strip}) " : " "
|
275
|
+
retult = "#{swift_typealias.strip} = #{encrypted_class_name.strip}\n#{confuse_literals.strip}#{objc_literals}#{class_literals.strip}"
|
276
|
+
retult
|
277
|
+
end
|
278
|
+
|
279
|
+
###----- 处理swift 函数 ------
|
280
|
+
confuse_func_pre_literal = "#BBConfuseMixObjcFunc"
|
281
|
+
if line_scrub.strip.start_with?(confuse_func_pre_literal)
|
282
|
+
#BBConfuseMixObjc("#selector(abcdefg(in:sencName:))"); asdasagwtrqwetr
|
283
|
+
|
284
|
+
|
285
|
+
#selector(.*?)\)
|
286
|
+
#解析带参数的
|
287
|
+
# line_scrub.gsub!(/#{confuse_func_pre_literal}\(#selector\((.*?)\)\)\);(?:.*?@objc\((\S+)\))?(?:.*?@objc\s*)?/) do |match|
|
288
|
+
line_scrub.gsub!(/#{confuse_func_pre_literal}\((?:#selector\((.*?)\)\))?(?:"([^"]*:[^"]*)")?\);(?:.*?@objc\((\S+)\))?(?:.*?@objc\s*)?/) do |match|
|
289
|
+
modified = true
|
290
|
+
selector_match = $1
|
291
|
+
str_match = $2
|
292
|
+
# puts "检测到混淆函数标记(带参数) = #{match};$1 = #{$1} $2 = #{$2} $3 = #{$3}"
|
293
|
+
is_selector = selector_match && !selector_match.empty?
|
294
|
+
if is_selector
|
295
|
+
apis = handleObjcInsert(match,selector_match,line)
|
296
|
+
else
|
297
|
+
apis = str_match.split(':').map(&:strip)
|
298
|
+
end
|
299
|
+
result,apis_define_map_temp = encrypted_and_combination_api(apis,match)
|
300
|
+
apis_define_map = apis_define_map.merge(apis_define_map_temp)
|
301
|
+
result
|
302
|
+
end
|
303
|
+
|
304
|
+
#解析不带参数的
|
305
|
+
# line_scrub.gsub!(/#{confuse_func_pre_literal}\(#selector\(([^\(]+)\)\);(?:.*?@objc\((\S+)\))?(?:.*?@objc\s*)?/) do |match|
|
306
|
+
line_scrub.gsub!(/#{confuse_func_pre_literal}\((?:#selector\(([^\(]+)\))?(?:"([^":]+)")?\);(?:.*?@objc\((\S+)\))?(?:.*?@objc\s*)?/) do |match|
|
307
|
+
# line_scrub.gsub!(/#{confuse_func_pre_literal}\((#selector\((.*?)\)|"([^"]+)")\);(?:.*?@objc\((\S+)\))?(?:.*?@objc\s*)?/) do |match|
|
308
|
+
modified = true
|
309
|
+
selector_match = $1
|
310
|
+
str_match = $2
|
311
|
+
# puts "检测到混淆函数标记(无参数) = #{match};$1 = #{$1} $2 = #{$2} $3 = #{$3}"
|
312
|
+
is_selector = selector_match && !selector_match.empty?
|
313
|
+
apis = []
|
314
|
+
if is_selector
|
315
|
+
apis = handleObjcInsert(match,selector_match,line)
|
316
|
+
else
|
317
|
+
apis = str_match.split(':').map(&:strip) if str_match
|
318
|
+
end
|
319
|
+
result,apis_define_map_temp = encrypted_and_combination_api(apis,match)
|
320
|
+
apis_define_map = apis_define_map.merge(apis_define_map_temp)
|
321
|
+
result
|
322
|
+
end
|
323
|
+
end
|
324
|
+
# puts "line_scrub = #{line_scrub}"
|
325
|
+
end
|
326
|
+
|
327
|
+
#每行结束时,重置行标识
|
328
|
+
in_line_comment = false
|
329
|
+
last_line_scrub = line_scrub
|
330
|
+
line_scrub
|
331
|
+
end
|
332
|
+
# 写回修改后的文件
|
333
|
+
if modified
|
334
|
+
encrypted_lines = encrypted_lines.each_with_index.reject { |_, index| need_delete_line_map.keys.include?(index) }.map(&:first)
|
335
|
+
|
336
|
+
File.write(file_path, encrypted_lines.join)
|
337
|
+
# puts "已混淆文件:#{file_path}"
|
338
|
+
# File.open('/Users/masterfly/Desktop/babybusGit/common/SafetyProtection/Pod/Classes/ReplaceMe.swift', 'w') do |file|
|
339
|
+
# # 逐行写入 rows
|
340
|
+
# lines.each do |row|
|
341
|
+
# file.puts(row)
|
342
|
+
# puts "插入:#{row}"
|
343
|
+
# end
|
344
|
+
# end
|
345
|
+
puts "已混淆文件:#{file_path}"
|
346
|
+
end
|
347
|
+
return apis_define_map, swift_extension_funcBody_map
|
348
|
+
end
|
349
|
+
|
350
|
+
|
351
|
+
def handleObjcInsert(match, suffix,line)
|
352
|
+
|
353
|
+
#match = #BBConfuseMixObjcFunc(#selector(swiftTestPar(in:sencName:))); @objc(blbbYmRPLbOb:etMLJynbSjJy:)
|
354
|
+
#suffix = swiftTestPar(in:sencName:
|
355
|
+
|
356
|
+
#第一步, 使用;分割,获取关键信息 #BBConfuseMixObjcFunc(#selector(swiftTestPar(in:sencName:)))
|
357
|
+
literals = match.split(';').map(&:strip)
|
358
|
+
confuse_literals = literals.first
|
359
|
+
func_literals = literals[1]
|
360
|
+
|
361
|
+
#“swiftTestPar(in:sencName:” --》 [“swiftTestPar,“in:sencName:”]
|
362
|
+
sepFunc = suffix.split('(').map(&:strip)
|
363
|
+
|
364
|
+
funcName = sepFunc
|
365
|
+
paramSplit = []
|
366
|
+
if sepFunc.length > 0
|
367
|
+
#““swiftTestPar”
|
368
|
+
funcName = sepFunc.first
|
369
|
+
|
370
|
+
#in:sencName:
|
371
|
+
params = sepFunc[1]
|
372
|
+
|
373
|
+
#in:sencName: --> ["in","sencName"]
|
374
|
+
if params
|
375
|
+
paramSplit = params.split(':')
|
376
|
+
|
377
|
+
#特殊情况处理
|
378
|
+
#首个参数为 _ 则个参数返回空
|
379
|
+
# 其他参数使用With + 参数首字符大写
|
380
|
+
paramSplit = paramSplit.map.with_index do |seg, index|
|
381
|
+
if index == 0 && seg == "_"
|
382
|
+
""
|
383
|
+
elsif index == 0
|
384
|
+
"With#{seg.capitalize}"
|
385
|
+
else
|
386
|
+
seg
|
387
|
+
end
|
388
|
+
end
|
389
|
+
|
390
|
+
funcName = funcName + paramSplit.first
|
391
|
+
paramSplit.slice!(0)
|
392
|
+
end
|
393
|
+
end
|
394
|
+
|
395
|
+
apis = [funcName] + paramSplit
|
396
|
+
return apis
|
397
|
+
end
|
398
|
+
|
399
|
+
def encrypted_and_combination_api(apis,match)
|
400
|
+
new_parts = encrypted_api(apis)
|
401
|
+
|
402
|
+
# 构建新注解内容
|
403
|
+
new_annotation = "#{new_parts.join(':')}"
|
404
|
+
if match.include?(":")
|
405
|
+
new_annotation = "#{new_annotation}:"
|
406
|
+
end
|
407
|
+
|
408
|
+
apis_define_map = {}
|
409
|
+
# 将未混淆的 API 名称及其对应的混淆字符串添加到字典中
|
410
|
+
# apis.each_with_index do |seg, index|
|
411
|
+
# apis_define_map[seg.strip] = new_parts[index]
|
412
|
+
# end
|
413
|
+
|
414
|
+
#仅混淆函数名称, 参数可能太过简单,宏定义有风险
|
415
|
+
apis_define_map[apis.first] = new_parts.first if apis && !apis.empty?
|
416
|
+
|
417
|
+
result = match.gsub(";","").gsub(/@objc\([^)]*\)|@objc\s+/, "") # 删除分号 和多余的 @objc
|
418
|
+
result = "#{result.strip}; @objc(#{new_annotation})" # 添加新的注解
|
419
|
+
# puts "result = #{result}"
|
420
|
+
return result, apis_define_map
|
421
|
+
end
|
422
|
+
|
423
|
+
|
424
|
+
#搜索所有子文件夹
|
425
|
+
def search_files(folder_paths, exclude_folders)
|
426
|
+
# 获取文件夹下所有文件(包括子文件夹)
|
427
|
+
all_files = []
|
428
|
+
folder_paths.each do |folder|
|
429
|
+
# 不再做额外格式过滤,避免和podspec中source_files 自带的格式冲突
|
430
|
+
# allowed_extensions = ['m', 'c', 'swift', 'mm', 'hap', 'cpp']
|
431
|
+
# pattern = File.join(folder, '**', '*.{'+allowed_extensions.join(',')+'}')
|
432
|
+
# all_files += Dir.glob(pattern, File::FNM_DOTMATCH).reject { |file| File.directory?(file) }
|
433
|
+
|
434
|
+
# 使用 Dir.glob 方法直接获取符合条件的文件路径
|
435
|
+
files_in_folder = Dir.glob(folder, File::FNM_DOTMATCH)
|
436
|
+
|
437
|
+
# 过滤掉目录路径,只保留文件路径,并将其添加到 all_files 数组中
|
438
|
+
all_files += files_in_folder.reject { |file| File.directory?(file) }
|
439
|
+
end
|
440
|
+
|
441
|
+
# 获取需要排除的文件
|
442
|
+
exclude_files = []
|
443
|
+
exclude_folders.each do |folder|
|
444
|
+
files_in_folder = Dir.glob(folder, File::FNM_DOTMATCH)
|
445
|
+
exclude_files += files_in_folder.reject { |file| File.directory?(file) }
|
446
|
+
end
|
447
|
+
|
448
|
+
# 剔除掉需要排除的文件
|
449
|
+
all_files = all_files.uniq - exclude_files.uniq
|
450
|
+
|
451
|
+
# 遍历文件进行检索
|
452
|
+
$apis_define_map = {}
|
453
|
+
$swift_extension_funcBody_map = {}
|
454
|
+
|
455
|
+
all_files.each_with_index do |file_path, index|
|
456
|
+
api_dict, funcBody_map = extract_annotated_attributes?(file_path)
|
457
|
+
$apis_define_map.merge!(api_dict)
|
458
|
+
funcBody_map.each do |key, value|
|
459
|
+
if $swift_extension_funcBody_map.key?(key)
|
460
|
+
# 如果 key 存在于 $swift_extension_funcBody_map 中,合并并去重
|
461
|
+
$swift_extension_funcBody_map[key] = (Array($swift_extension_funcBody_map[key]) + Array(value)).uniq
|
462
|
+
else
|
463
|
+
# 如果 key 不存在,直接添加
|
464
|
+
$swift_extension_funcBody_map[key] = value
|
465
|
+
end
|
466
|
+
end
|
467
|
+
end
|
468
|
+
return $apis_define_map, $swift_extension_funcBody_map
|
469
|
+
end
|
470
|
+
|
471
|
+
|
472
|
+
def encrypted_api(apis)
|
473
|
+
encrypted_api = ""
|
474
|
+
# 生成 #define 语句
|
475
|
+
defines = apis.map do |api|
|
476
|
+
if $apis_define_map.key?(api)
|
477
|
+
encrypted_api = $apis_define_map[api]
|
478
|
+
else
|
479
|
+
encrypted_api = generate_safe_api_key()
|
480
|
+
end
|
481
|
+
end
|
482
|
+
defines
|
483
|
+
end
|
484
|
+
|
485
|
+
def generate_safe_api_key
|
486
|
+
#需要排除这些连接词,如果有这些连接词,那么转swift时函数会被分割
|
487
|
+
forbidden_words = %w[
|
488
|
+
With In On To At As Of By For After Before During Alongside Under Through
|
489
|
+
]
|
490
|
+
|
491
|
+
loop do
|
492
|
+
encrypted_api = SecureRandom.alphanumeric(24)
|
493
|
+
encrypted_api = encrypted_api.strip
|
494
|
+
encrypted_api = encrypted_api.gsub(/\d/, 'b')
|
495
|
+
encrypted_api = encrypted_api.sub(/^./, encrypted_api[0].downcase)
|
496
|
+
encrypted_api = extend_version(encrypted_api)
|
497
|
+
|
498
|
+
# 检查是否包含禁用词
|
499
|
+
contains_forbidden = forbidden_words.any? { |word| encrypted_api.include?(word) }
|
500
|
+
|
501
|
+
# 一直循环直到不包含关键词
|
502
|
+
return encrypted_api unless contains_forbidden
|
503
|
+
end
|
504
|
+
end
|
505
|
+
end
|
506
|
+
end
|
@@ -0,0 +1,150 @@
|
|
1
|
+
require 'cocoapods-privacy/command'
|
2
|
+
require 'cocoapods-core/specification/dsl/attribute_support'
|
3
|
+
require 'cocoapods-core/specification/dsl/attribute'
|
4
|
+
require 'xcodeproj'
|
5
|
+
require 'plist'
|
6
|
+
require 'yaml'
|
7
|
+
|
8
|
+
module ConfuseModule
|
9
|
+
|
10
|
+
public
|
11
|
+
|
12
|
+
# 处理组件
|
13
|
+
def self.load_module(podspec_file_path)
|
14
|
+
# puts "podspec_file_path = #{podspec_file_path}"
|
15
|
+
specManager = BB::BBSpecManager.new(KSpecTypeConfuse)
|
16
|
+
puts "👇👇👇👇👇👇 Start analysis component confuse 👇👇👇👇👇👇"
|
17
|
+
confuse_hash = specManager.check(podspec_file_path)
|
18
|
+
confuse_hash.each do |confuse_file_path, hash|
|
19
|
+
source_files = hash[KSource_Files_Key]
|
20
|
+
exclude_files = hash[KExclude_Files_Key]
|
21
|
+
# puts "source_files = #{source_files}"
|
22
|
+
# puts "exclude_files = #{exclude_files}"
|
23
|
+
# puts "confuse_file_path = #{confuse_file_path}"
|
24
|
+
podspec = Pod::Specification.from_file(podspec_file_path)
|
25
|
+
version = podspec.version.to_s
|
26
|
+
version = version.gsub('.', '_') # Replace dots with underscores
|
27
|
+
|
28
|
+
hunter = Confuse::Hunter.new(version)
|
29
|
+
apis_define_map, swift_extension_funcBody_map = hunter.search_need_confuse_apis(source_files,exclude_files)
|
30
|
+
# puts "swift_extension_funcBody_map = #{swift_extension_funcBody_map}"
|
31
|
+
|
32
|
+
oc_confuse_file_path = "#{confuse_file_path}.h"
|
33
|
+
swift_confuse_file_path = "#{confuse_file_path}.swift"
|
34
|
+
hunter.insert_encrypted_apis_to_confuse_header(apis_define_map,oc_confuse_file_path,version)
|
35
|
+
hunter.insert_encrypted_apis_to_confuse_swift(swift_extension_funcBody_map,swift_confuse_file_path,version)
|
36
|
+
end
|
37
|
+
puts "👆👆👆👆👆👆 End analysis component confuse 👆👆👆👆👆👆"
|
38
|
+
end
|
39
|
+
|
40
|
+
# # 处理工程
|
41
|
+
# def self.load_project(folds,exclude_folds,installer)
|
42
|
+
# project_path = ConfuseUtils.project_path()
|
43
|
+
# confuse_folder_path = File.join(File.basename(project_path, File.extname(project_path)),ConfuseUtils.confuse_folder)
|
44
|
+
# confuse_file_path = File.join(confuse_folder_path,ConfuseUtils.confuse_name)
|
45
|
+
|
46
|
+
# #创建混淆头文件
|
47
|
+
# # 如果混淆头文件不存在,创建混淆文件
|
48
|
+
# unless File.exist?(confuse_file_path)
|
49
|
+
# puts "#{confuse_file_path}"
|
50
|
+
# ConfuseUtils.create_confuse_if_empty(confuse_file_path)
|
51
|
+
# end
|
52
|
+
|
53
|
+
# # 打开 Xcode 项目,在Confuse下 创建
|
54
|
+
# project = Xcodeproj::Project.open(File.basename(project_path))
|
55
|
+
# main_group = project.main_group
|
56
|
+
# resources_group = main_group.find_subpath('Confuse',false)
|
57
|
+
# if resources_group.nil?
|
58
|
+
# resources_group = main_group.new_group('Confuse',confuse_folder_path)
|
59
|
+
# end
|
60
|
+
|
61
|
+
# target = project.targets.first
|
62
|
+
# resources_build_phase = target.resources_build_phase
|
63
|
+
# # 如果不存在引用,创建新的引入xcode引用
|
64
|
+
# if resources_group.find_file_by_path(ConfuseUtils.confuse_name).nil?
|
65
|
+
# confuse_file_ref = resources_group.new_reference(ConfuseUtils.confuse_name,:group)
|
66
|
+
# confuse_file_ref.last_known_file_type = 'sourcecode.objc.h'
|
67
|
+
# resources_build_phase.add_file_reference(confuse_file_ref) # 将文件引用添加到 resources 构建阶段中
|
68
|
+
# end
|
69
|
+
|
70
|
+
# confuse_pch_file_path = ""
|
71
|
+
# # 遍历项目的所有 targets,添加或修改 PCH 文件的设置
|
72
|
+
# project.targets.each do |target|
|
73
|
+
# target.build_configurations.each do |config|
|
74
|
+
# # 获取当前的 Prefix Header 设置
|
75
|
+
# current_pch = config.build_settings['GCC_PREFIX_HEADER']
|
76
|
+
|
77
|
+
# puts "name = #{target.name}"
|
78
|
+
|
79
|
+
# # 如果当前没有设置 PCH 文件,则添加新的设置
|
80
|
+
# if current_pch.nil? || current_pch.empty?
|
81
|
+
# # 如果混淆PCH不存在,创建混淆文件
|
82
|
+
# confuse_pch_file_path = File.join(confuse_folder_path,ConfuseUtils.confuse_pch_name)
|
83
|
+
# unless File.exist?(confuse_pch_file_path)
|
84
|
+
# puts "confuse_pch_file_path = #{confuse_pch_file_path}"
|
85
|
+
# ConfuseUtils.create_confuse_if_empty(confuse_pch_file_path,ConfuseUtils.confuse_pch_content)
|
86
|
+
# end
|
87
|
+
|
88
|
+
# #pch 添加到xcode 索引
|
89
|
+
# if resources_group.find_file_by_path(ConfuseUtils.confuse_pch_name).nil?
|
90
|
+
# confuse_pch_file_ref = resources_group.new_reference(ConfuseUtils.confuse_pch_name,:group)
|
91
|
+
# confuse_pch_file_ref.last_known_file_type = 'sourcecode.objc.h'
|
92
|
+
# resources_build_phase.add_file_reference(confuse_pch_file_ref) # 将文件引用添加到 resources 构建阶段中
|
93
|
+
# puts "confuse_pch_file_ref = #{confuse_pch_file_ref}"
|
94
|
+
# end
|
95
|
+
|
96
|
+
# # pch 路径添加到build setting
|
97
|
+
# config.build_settings['GCC_PREFIX_HEADER'] = "$(SRCROOT)/#{ConfuseUtils.project_name}/#{ConfuseUtils.confuse_folder}/#{ConfuseUtils.confuse_pch_name}"
|
98
|
+
# else
|
99
|
+
|
100
|
+
# pch_file_name = File.basename(current_pch)
|
101
|
+
# confuse_pch_file_path = Dir.glob("**/#{pch_file_name}").first
|
102
|
+
|
103
|
+
# # 如果 PCH 文件已设置,检查并修改文件内容
|
104
|
+
# if File.exist?(confuse_pch_file_path)
|
105
|
+
# file_content = File.read(confuse_pch_file_path)
|
106
|
+
|
107
|
+
# # 检查是否已包含
|
108
|
+
# unless file_content.include?("#{ConfuseUtils.confuse_name}")
|
109
|
+
# # 找到最后一个 #endif,插入新的 import 语句
|
110
|
+
# last_ifdef_index = file_content.rindex('#endif')
|
111
|
+
|
112
|
+
# if last_ifdef_index
|
113
|
+
# inser_content = "\n//混淆需要的头文件,不能删除\n#import \"#{ConfuseUtils.confuse_name}\"\n"
|
114
|
+
# puts "检测到已存在pch#{confuse_pch_file_path}, 直接在现在pch 文件中插入混淆头部文件 #{inser_content}"
|
115
|
+
# file_content.insert(last_ifdef_index,inser_content)
|
116
|
+
# File.write(confuse_pch_file_path, file_content)
|
117
|
+
# end
|
118
|
+
# end
|
119
|
+
# end
|
120
|
+
# end
|
121
|
+
# end
|
122
|
+
# end
|
123
|
+
|
124
|
+
# version = "" #内部使用随机字符串,不需要版本
|
125
|
+
# # #获取工程版本号,用来做动态混淆,每个确保每个版本都不一致
|
126
|
+
# # plist_path = target.resolved_build_setting('INFOPLIST_FILE', resolve_against: target).first
|
127
|
+
# # plist_path = File.join(File.dirname(project_path), plist_path)
|
128
|
+
# # plist = Plist.parse_xml(plist_path)
|
129
|
+
# # unless plist.nil?
|
130
|
+
# # version = plist['CFBundleShortVersionString']
|
131
|
+
# # end
|
132
|
+
|
133
|
+
# project.save
|
134
|
+
|
135
|
+
|
136
|
+
# # installer.pod_target_subprojects.flat_map { |p| p.targets }.each do |target|
|
137
|
+
# # target.build_configurations.each do |config|
|
138
|
+
# # puts "name2 = #{target.name}"
|
139
|
+
# # config.build_settings['GCC_PREFIX_HEADER'] = "$(SRCROOT)/#{ConfuseUtils.project_name}/#{ConfuseUtils.confuse_folder}/#{ConfuseUtils.confuse_pch_name}"
|
140
|
+
# # end
|
141
|
+
# # end
|
142
|
+
|
143
|
+
# # 开始检索api,并返回json 字符串数据
|
144
|
+
# hunter = ConfuseHunter.new("")
|
145
|
+
# apis = hunter.search_need_confuse_apis(folds,exclude_folds)
|
146
|
+
|
147
|
+
# # 将数据写入混淆文件
|
148
|
+
# hunter.insert_encrypted_apis_to_confuse_header(apis,confuse_file_path,version)
|
149
|
+
# end
|
150
|
+
end
|