packages feed

encapsule-0.5: src/Script.hs

{-# LANGUAGE ExtendedDefaultRules #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RecordWildCards #-}

-- SPDX-License-Identifier: Apache-2.0


module Script (
  SwitchUser(..),
  chooseSwitchUser,
  canSwitchUser,
  switchUserArgs,
  switchLabel,
  setupScript,
  Setup(..)
  )
where

import Control.Monad (unless, when)
import Control.Monad.Shell
import Data.Maybe (isNothing)
import qualified Data.Text.Lazy as T
import System.FilePath ((</>))
import System.Posix.IO

default (T.Text)

data SwitchUser = Runuser | Sudo | None

chooseSwitchUser :: Bool -> Bool -> SwitchUser
chooseSwitchUser True _     = Runuser
chooseSwitchUser False True = Sudo
chooseSwitchUser _ _        = None

canSwitchUser :: SwitchUser -> Bool
canSwitchUser None = False
canSwitchUser _    = True

-- argv prefix; empty for None
switchUserArgs :: SwitchUser -> String -> [String]
switchUserArgs Runuser u = ["runuser", "-u", u, "--"]
switchUserArgs Sudo    u = ["sudo", "-n", "--preserve-env", "-u", u, "--"]
switchUserArgs None    _ = []

switchLabel :: SwitchUser -> String
switchLabel Runuser = "runuser"
switchLabel Sudo    = "sudo"
switchLabel None    = "none"

data Setup = Setup
  { nosudo :: Bool
  , noskel :: Bool
  , username :: T.Text
  , program :: String
  , createhome :: Bool
  , homedir :: T.Text
  , mprojectDir :: Maybe FilePath
  }

setupScript :: Bool -> SwitchUser -> Bool -> Setup -> String
setupScript dbg switch haveSudo (Setup {..}) =
  T.unpack . T.replace "\t" " " . linearScript $
  sudoSetup >> homeSetup
  where
    redir s dest =
        if dbg then s else s |> (dest :: String) &stdError>&stdOutput
    runHide c args = run c args `redir` "/dev/null"
    -- haveCmd c = runHide "command" ["-v",c]

    sudoSetup =
      when haveSudo $
      unless nosudo $
      let sudoers = "/etc/sudoers.d" in
          whenCmd (test $ TDirExists sudoers) $ do
          runHide "echo" [username, "ALL=(ALL) NOPASSWD:ALL"] `redir` (sudoers </> program)
          runHide "chmod" ["440", T.pack sudoers]

    homeSetup = do
      when createhome $ do
        runHide "mkdir" ["-p", homedir]
        runHide "chown" [username, homedir]
      unless noskel $
        when (canSwitchUser switch) $
        whenCmd
        (test (TDirExists homedir)
         -&&-
         test (TDirExists (T.pack "/etc/skel"))) $
        let cpArgs = ["-a", "--update=none", "/etc/skel/.", homedir <> "/"]
        in case map T.pack $ switchUserArgs switch (T.unpack username) of
             prog:args -> runHide prog $ args ++ "cp" : cpArgs
             [] -> return ()
      when (isNothing mprojectDir && createhome) $
       runHide "cd" [homedir]