5 changed files with 144 additions and 45 deletions
@ -0,0 +1,104 @@
|
||||
package auth |
||||
|
||||
import ( |
||||
"fmt" |
||||
"os/exec" |
||||
"regexp" |
||||
"strconv" |
||||
"time" |
||||
|
||||
"github.com/Riyyi/declpac/pkg/log" |
||||
) |
||||
|
||||
var tool string |
||||
var timeout time.Duration = 5 * time.Minute |
||||
var refreshCommand []string = []string{"-n", "true"} |
||||
|
||||
// -----------------------------------------
|
||||
// public
|
||||
|
||||
func Command(name string, args ...string) *exec.Cmd { |
||||
if tool == "" { |
||||
return log.Command(name, args...) |
||||
} |
||||
args = append([]string{name}, args...) |
||||
return log.Command(tool, args...) |
||||
} |
||||
|
||||
func Run() { |
||||
exec.Command(tool, refreshCommand...).Run() |
||||
} |
||||
|
||||
func Start() error { |
||||
err := detect() |
||||
if err != nil { |
||||
return err |
||||
} |
||||
|
||||
// Automatically refresh privilege elevation to prevent user prompts
|
||||
go func() { |
||||
for { |
||||
Run() |
||||
time.Sleep(timeout) |
||||
} |
||||
}() |
||||
|
||||
return nil |
||||
} |
||||
|
||||
// -----------------------------------------
|
||||
// private
|
||||
|
||||
func detect() error { |
||||
tool = getTool() |
||||
if tool == "" { |
||||
return fmt.Errorf("no privilege elevation tool detected in PATH") |
||||
} |
||||
|
||||
parseTimeout() |
||||
// We have to be a little faster than the actual timeout
|
||||
timeout -= 30 * time.Second |
||||
|
||||
return nil |
||||
} |
||||
|
||||
func execLookPath(name string) string { |
||||
path, err := exec.LookPath(name) |
||||
if err != nil { |
||||
return "" |
||||
} |
||||
return path |
||||
} |
||||
|
||||
func getTool() string { |
||||
sudo := execLookPath("sudo") |
||||
doas := execLookPath("doas") |
||||
|
||||
if sudo != "" { |
||||
return "sudo" |
||||
} |
||||
if doas != "" { |
||||
return "doas" |
||||
} |
||||
|
||||
return "" |
||||
} |
||||
|
||||
func parseTimeout() { |
||||
switch tool { |
||||
case "sudo": |
||||
out, err := exec.Command("sudo", "sudo", "-V").CombinedOutput() |
||||
if err != nil { |
||||
return |
||||
} |
||||
re := regexp.MustCompile(`Authentication timestamp timeout: (\d+)\..*`) |
||||
matches := re.FindStringSubmatch(string(out)) |
||||
if len(matches) == 2 { |
||||
if minutes, err := strconv.Atoi(matches[1]); err == nil { |
||||
timeout = time.Duration(minutes) * time.Minute |
||||
} |
||||
} |
||||
case "doas": |
||||
exec.Command("doas", "true").Run() |
||||
} |
||||
} |
||||
Loading…
Reference in new issue