Merge pull request #35 from murphyjt/fix-escaping
Some checks failed
cia-unix build / release (${{ github.event.repository.name }}, ${{ github.event.repository.name }}-linux-arm64, ubuntu-22.04-arm) (push) Has been cancelled
cia-unix build / release (${{ github.event.repository.name }}, ${{ github.event.repository.name }}-linux-x86_64, ubuntu-latest) (push) Has been cancelled
cia-unix build / release (${{ github.event.repository.name }}, ${{ github.event.repository.name }}-macos-arm64, macos-latest) (push) Has been cancelled
cia-unix build / release (${{ github.event.repository.name }}, ${{ github.event.repository.name }}-macos-x86_64, macos-13) (push) Has been cancelled

Replace shell backticks with Process.new for better escaping
This commit is contained in:
Nishijima Akito 2025-05-19 15:19:08 +02:00 committed by GitHub
commit f33b9b2fc7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -1,7 +1,7 @@
require "colorize" require "colorize"
log : File = File.new "cia-unix.log", "w" LOG = File.new "cia-unix.log", "w"
log.puts Time.utc.to_s LOG.puts Time.utc.to_s
# dependencies check # dependencies check
tools = ["./ctrtool", "./ctrdecrypt", "./makerom", "seeddb.bin"] tools = ["./ctrtool", "./ctrdecrypt", "./makerom", "seeddb.bin"]
@ -9,13 +9,13 @@ tools.each do |tool|
case tool case tool
when "./ctrtool", "./ctrdecrypt", "./makerom" when "./ctrtool", "./ctrdecrypt", "./makerom"
if !File.exists? %x[which #{tool}].chomp if !File.exists? %x[which #{tool}].chomp
log.delete if File.exists? "cia-unix.log" LOG.delete if File.exists? "cia-unix.log"
download_dep download_dep
abort "#{tool.lchop("./").colorize.mode(:bold)} not found. Make sure it's located in the #{"same directory".colorize.mode(:underline)}" if !File.exists? tool abort "#{tool.lchop("./").colorize.mode(:bold)} not found. Make sure it's located in the #{"same directory".colorize.mode(:underline)}" if !File.exists? tool
end end
when "seeddb.bin" when "seeddb.bin"
if !File.exists? tool if !File.exists? tool
log.delete if File.exists? "cia-unix.log" LOG.delete if File.exists? "cia-unix.log"
download_dep download_dep
abort "#{tool.colorize.mode(:bold)} not found. Make sure it's located in the #{"same directory".colorize.mode(:underline)}" if !File.exists? tool abort "#{tool.colorize.mode(:bold)} not found. Make sure it's located in the #{"same directory".colorize.mode(:underline)}" if !File.exists? tool
end end
@ -31,10 +31,19 @@ end
# roms presence check # roms presence check
if Dir["*.cia"].size.zero? && Dir["*.3ds"].size.zero? if Dir["*.cia"].size.zero? && Dir["*.3ds"].size.zero?
log.delete if File.exists? "cia-unix.log" LOG.delete if File.exists? "cia-unix.log"
abort "No #{"CIA".colorize.mode(:bold)}/#{"3DS".colorize.mode(:bold)} roms were found." abort "No #{"CIA".colorize.mode(:bold)}/#{"3DS".colorize.mode(:bold)} roms were found."
end end
def run_tool(name : String, args : Array(String)) : String
process = Process.new("./#{name}", args: args, output: Process::Redirect::Pipe)
content = process.output.gets_to_end
LOG.puts content
exit_code = process.wait.exit_code
raise "#{name} failed with exit code #{exit_code}" if exit_code != 0
content
end
def check_decrypt(name : String, ext : String) def check_decrypt(name : String, ext : String)
if File.exists? "#{name}-decrypted.#{ext}" if File.exists? "#{name}-decrypted.#{ext}"
puts "Decryption completed\n".colorize.mode(:underline) puts "Decryption completed\n".colorize.mode(:underline)
@ -43,11 +52,11 @@ def check_decrypt(name : String, ext : String)
end end
end end
def gen_args(name : String, part_count : Int32) : String def gen_args(name : String, part_count : Int32) : Array(String)
args : String = "" args = [] of String
part_count.times do |partition| part_count.times do |partition|
if File.exists? "#{name}.#{partition}.ncch" if File.exists? "#{name}.#{partition}.ncch"
args += "-i '#{name}.#{partition}.ncch:#{partition}:#{partition}' " args += ["-i", "#{name}.#{partition}.ncch:#{partition}:#{partition}"]
end end
end end
return args return args
@ -60,18 +69,16 @@ def remove_cache
Dir["*.ncch"].each do |fname| File.delete(fname) end Dir["*.ncch"].each do |fname| File.delete(fname) end
end end
args : String = ""
# 3ds decrypting # 3ds decrypting
Dir["*.3ds"].each do |ds| Dir["*.3ds"].each do |ds|
next if ds.includes? "decrypted" next if ds.includes? "decrypted"
args = ""
i : UInt8 = 0 i : UInt8 = 0
dsn : String = ds.chomp ".3ds" dsn : String = ds.chomp ".3ds"
args = ["-f", "cci", "-ignoresign", "-target", "p", "-o", "#{dsn}-decrypted.3ds"]
puts "Decrypting: #{ds.colorize.mode(:bold)}..." puts "Decrypting: #{ds.colorize.mode(:bold)}..."
log.puts %x[./ctrdecrypt '#{ds}'] run_tool("ctrdecrypt", [ds])
Dir["#{dsn}.*.ncch"].each do |ncch| Dir["#{dsn}.*.ncch"].each do |ncch|
case ncch case ncch
@ -92,10 +99,10 @@ Dir["*.3ds"].each do |ds|
when "#{dsn}.UpdateData.ncch" when "#{dsn}.UpdateData.ncch"
i = 7 i = 7
end end
args += "-i '#{ncch}:#{i}:#{i}' " args += ["-i", "#{ncch}:#{i}:#{i}"]
end end
puts "Building decrypted #{dsn} 3DS..." puts "Building decrypted #{dsn} 3DS..."
log.puts %x[./makerom -f cci -ignoresign -target p -o '#{dsn}-decrypted.3ds' #{args}] run_tool("makerom", args)
check_decrypt(dsn, "3ds") check_decrypt(dsn, "3ds")
remove_cache remove_cache
end end
@ -106,39 +113,41 @@ Dir["*.cia"].each do |cia|
puts "Decrypting: #{cia.colorize.mode(:bold)}..." puts "Decrypting: #{cia.colorize.mode(:bold)}..."
cutn : String = cia.chomp ".cia" cutn : String = cia.chomp ".cia"
args = "" content = run_tool("ctrtool", ["--seeddb=seeddb.bin", cia])
content = %x[./ctrtool --seeddb=seeddb.bin '#{cia}']
# game # game
if content.match /T.*d.*00040000/ if content.match /T.*d.*00040000/
puts "CIA Type: Game" puts "CIA Type: Game"
log.puts %x[./ctrdecrypt '#{cia}'] run_tool("ctrdecrypt", [cia])
args = ["-f", "cia", "-ignoresign", "-target", "p", "-o", "#{cutn}-decfirst.cia"]
i : UInt8 = 0 i : UInt8 = 0
Dir["*.ncch"].sort.each do |ncch| Dir["*.ncch"].sort.each do |ncch|
args += "-i '#{ncch}:#{i}:#{i}' " args += ["-i", "#{ncch}:#{i}:#{i}"]
i += 1 i += 1
end end
log.puts %x[./makerom -f cia -ignoresign -target p -o '#{cutn}-decfirst.cia' #{args}] run_tool("makerom", args)
# patch # patch
elsif content.match /T.*d.*0004000(e|E)/ elsif content.match /T.*d.*0004000(e|E)/
puts "CIA Type: #{"Patch".colorize.mode(:bold)}" puts "CIA Type: #{"Patch".colorize.mode(:bold)}"
log.puts %x[./ctrdecrypt '#{cia}'] run_tool("ctrdecrypt", [cia])
args = ["-f", "cia", "-ignoresign", "-target", "p", "-o", "#{cutn} (Patch)-decrypted.cia"]
patch_parts : Int32 = Dir["#{cutn}.*.ncch"].size patch_parts : Int32 = Dir["#{cutn}.*.ncch"].size
args = gen_args(cutn, patch_parts) args += gen_args(cutn, patch_parts)
log.puts %x[./makerom -f cia -ignoresign -target p -o '#{cutn} (Patch)-decrypted.cia' #{args}] run_tool("makerom", args)
check_decrypt("#{cutn} (Patch)", "cia") check_decrypt("#{cutn} (Patch)", "cia")
# dlc # dlc
elsif content.match /T.*d.*0004008(c|C)/ elsif content.match /T.*d.*0004008(c|C)/
puts "CIA Type: #{"DLC".colorize.mode(:bold)}" puts "CIA Type: #{"DLC".colorize.mode(:bold)}"
log.puts %x[./ctrdecrypt '#{cia}'] run_tool("ctrdecrypt", [cia])
args = ["-f", "cia", "-dlc", "-ignoresign", "-target", "p", "-o", "#{cutn} (DLC)-decrypted.cia"]
dlc_parts : Int32 = Dir["#{cutn}.*.ncch"].size dlc_parts : Int32 = Dir["#{cutn}.*.ncch"].size
args = gen_args(cutn, dlc_parts) args += gen_args(cutn, dlc_parts)
log.puts %x[./makerom -f cia -dlc -ignoresign -target p -o '#{cutn} (DLC)-decrypted.cia' #{args}] run_tool("makerom", args)
check_decrypt("#{cutn} (DLC)", "cia") check_decrypt("#{cutn} (DLC)", "cia")
else else
puts "Unsupported CIA" puts "Unsupported CIA"
@ -148,13 +157,13 @@ Dir["*.cia"].each do |cia|
cutn = decfirst.chomp "-decfirst.cia" cutn = decfirst.chomp "-decfirst.cia"
puts "Building decrypted #{cutn} CCI..." puts "Building decrypted #{cutn} CCI..."
log.puts %x[./makerom -ciatocci '#{decfirst}' -o '#{cutn}-decrypted.cci'] run_tool("makerom", ["-ciatocci", decfirst, "-o", "#{cutn}-decrypted.cci"])
check_decrypt(cutn, "cci") check_decrypt(cutn, "cci")
end end
remove_cache remove_cache
end end
log.flush LOG.flush
log.close LOG.close
puts "Log saved" puts "Log saved"