-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcsvToLangFiles.rb
More file actions
201 lines (128 loc) · 5.08 KB
/
csvToLangFiles.rb
File metadata and controls
201 lines (128 loc) · 5.08 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
#!/usr/bin/env ruby
# encoding: UTF-8
require 'csv'
require 'fileutils' # ✅ IMPROVEMENT: Safer directory creation
USAGE = <<END
Convert a CSV file to Localizable.strings files
Usage: run 'ruby csvToLangFiles.rb translations.csv'
translations.csv can have different name
END
# 🔒 SECURITY CHANGE: Limit max input file size (50 MB)
MAX_FILE_SIZE = 50 * 1024 * 1024
# 🔒 SECURITY CHANGE: Base output directory
BASE_OUTPUT_DIR = File.expand_path("CHANGE ME TO YOUR OUTPUT DIRECTORY")
def die_with_usage(msg=nil)
puts USAGE
puts msg if msg
exit
end
# 🔒 SECURITY CHANGE: Escape strings for .strings format
def escape_strings(value)
return "" if value.nil?
value.to_s
.gsub("\\", "\\\\")
.gsub('"', '\"')
.gsub("\n", "\\n")
end
# 🔒 SECURITY CHANGE: Sanitize language folder names
def sanitize_language(lang)
clean = lang.to_s.gsub(/[^a-zA-Z0-9_-]/, '')
raise "Invalid language code: #{lang}" if clean.empty?
clean
end
# 🔒 SECURITY CHANGE: Prevent path traversal
def safe_path(base, target)
full = File.expand_path(target, base)
unless full.start_with?(base)
raise "Unsafe path detected: #{full}"
end
full
end
filename = ARGV[0]
die_with_usage "You must pass a file." unless filename
die_with_usage "File does not exist." unless File.exist?(filename)
die_with_usage "File is too large (max 50MB)." if File.size(filename) > MAX_FILE_SIZE
csvArray = []
# reading file
begin
CSV.foreach(filename, encoding: "UTF-8") do |row|
csvArray << row
end
rescue => e
die_with_usage "Failed to read CSV file: #{e.message}"
end
output = STDOUT
# ✅ IMPROVEMENT: Simplified counter
puts "Lines in file: #{csvArray.length}"
languageArray = []
csvArray.each do |row|
languageArray = row
puts "Top Columns #{languageArray}"
break
end
fileIndex = 1
begin
puts("Loop fileIndex = #{fileIndex}")
# 🔒 SECURITY CHANGE: Sanitize language name
lang = sanitize_language(languageArray[fileIndex])
# 🔒 SECURITY CHANGE: Safe directory path
dir_path = safe_path(
BASE_OUTPUT_DIR,
"#{lang}.lproj"
)
# 🔒 SECURITY CHANGE: Safe directory creation
unless File.directory?(dir_path)
puts "Creating #{dir_path}"
FileUtils.mkdir_p(dir_path)
end
file_path = safe_path(
BASE_OUTPUT_DIR,
"#{lang}.lproj/Localizable.strings"
)
puts "Opening file Localizable.strings for writing"
# 🔒 SECURITY CHANGE: Prevent accidental overwrite
if File.exist?(file_path)
puts "Warning: Overwriting existing file: #{file_path}"
end
output = File.open(file_path, "w", encoding: "UTF-8")
output.write "\n// Localizable.strings\n//\n// Please do not edit this file. \n// This file should be automatically generated.\n//\n\n"
rowCounter = 0
lastStoredSeparatorName = ""
puts "Go through each line of previously saved csv file"
csvArray.each do |row|
if rowCounter != 0
# Separator
if row[0] != nil && row[0].start_with?('#')
if lastStoredSeparatorName.length > 0
output.write "//=== #{lastStoredSeparatorName}\n\n\n"
end
# 🔒 SECURITY CHANGE: Safer gsub (no bang)
adjustedRowName = row[0].to_s.gsub('#', '')
output.write "//--- #{adjustedRowName}\n"
lastStoredSeparatorName = adjustedRowName
else
if row[0] != nil && row[0].length > 0
key = escape_strings(row[0])
# remove wrapping quotes
quatedValue = row[fileIndex]
quatedValue = quatedValue&.start_with?('"') && quatedValue&.end_with?('"') ? quatedValue[1..-2] : quatedValue
value = escape_strings(quatedValue)
# 🔒 SECURITY CHANGE: Generic float handling
if value =~ /^\d+\.0$/
value = value.to_i.to_s
end
if value != nil && value.length > 0
output.write "\"#{key}\" = \"#{value}\";\n"
end
else
output.write "\n"
end
end
end
rowCounter += 1
end
if lastStoredSeparatorName.length > 0
output.write "//=== #{lastStoredSeparatorName}"
end
fileIndex += 1
end while fileIndex < languageArray.count