Skip to content

Commit 5711594

Browse files
authored
Create sudo.cr
1 parent 522d196 commit 5711594

1 file changed

Lines changed: 87 additions & 0 deletions

File tree

source-code/update-system/sudo.cr

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
# ── Sudo state ────────────────────────────────────────────────────────────────
2+
module SudoState
3+
@@password : String = ""
4+
5+
def self.password=(pwd : String)
6+
@@password = pwd
7+
end
8+
9+
def self.password : String
10+
@@password
11+
end
12+
end
13+
14+
# ── Command runners ───────────────────────────────────────────────────────────
15+
def run_command(cmd : String) : Bool
16+
Process.run(
17+
cmd,
18+
shell: true,
19+
input: Process::Redirect::Inherit,
20+
output: Process::Redirect::Inherit,
21+
error: Process::Redirect::Inherit
22+
).success?
23+
end
24+
25+
def capture_command(cmd : String) : {Bool, String}
26+
buf = IO::Memory.new
27+
status = Process.run(cmd, shell: true, input: Process::Redirect::Close, output: buf, error: buf)
28+
{status.success?, buf.to_s}
29+
end
30+
31+
# Run sudo command with password piped via stdin — bypasses TTY cache issues.
32+
def sudo_run(cmd : String) : Bool
33+
full = "echo #{Process.quote(SudoState.password)} | sudo -S sh -c #{Process.quote(cmd)} 2>/dev/null"
34+
Process.run(
35+
full,
36+
shell: true,
37+
input: Process::Redirect::Close,
38+
output: Process::Redirect::Inherit,
39+
error: Process::Redirect::Inherit
40+
).success?
41+
end
42+
43+
# ── Sudo password prompt ──────────────────────────────────────────────────────
44+
def prompt_sudo_password : String
45+
puts ""
46+
puts " #{"".colorize(:dark_gray)} #{"Sudo authentication".colorize(:white).bold}"
47+
puts " #{"".colorize(:dark_gray)} #{"Password is piped directly to each sudo call — no repeated prompts.".colorize(:dark_gray)}"
48+
print " #{"".colorize(:dark_gray)} #{"password".colorize(:white)}"
49+
50+
password = ""
51+
STDIN.raw do |io|
52+
loop do
53+
byte = io.read_byte
54+
break if byte.nil?
55+
char = byte.chr
56+
break if char == '\r' || char == '\n'
57+
if char == '\u007F' || char == '\b'
58+
unless password.empty?
59+
password = password[0..-2]
60+
print "\b \b"
61+
end
62+
next
63+
end
64+
password += char.to_s
65+
print "*"
66+
end
67+
end
68+
puts ""
69+
70+
validated = Process.run(
71+
"echo #{Process.quote(password)} | sudo -S true 2>/dev/null",
72+
shell: true,
73+
input: Process::Redirect::Close,
74+
output: Process::Redirect::Close,
75+
error: Process::Redirect::Close
76+
).success?
77+
78+
unless validated
79+
puts ""
80+
puts " #{"".colorize(:red).bold} #{"Incorrect password — aborting.".colorize(:red)}"
81+
exit(1)
82+
end
83+
84+
puts " #{"".colorize(:green).bold} #{"Authentication successful.".colorize(:light_gray)}"
85+
puts ""
86+
password
87+
end

0 commit comments

Comments
 (0)