packages feed

swiss-army-knife-1.1.0.2: lib/Knives/WireGuard.hs

{-# LANGUAGE OverloadedStrings #-}
{-# OPTIONS_GHC -Wno-unused-top-binds #-}

module Knives.WireGuard where

import Utils (systemctl)
import CommandLine
-- import System.IO
-- import System.Process
import System.Directory (getDirectoryContents)
import System.FilePath (dropExtension, takeExtension)
import Control.Monad (when)
import Data.List

knifeWireGuard :: WireGuardOptions -> IO ()
knifeWireGuard WireGuardOptions { listWGs
                                , activateWG
                                , enableWG
                                , deactivateWG
                                , disableWG
                                , reactivateWG}
  | checkMutualExclusivity = do
      wgs <- wgList
      ss  <- wgStatus wgs
      when listWGs $ putStrLn $ formatStatus ss
      case (activateWG , enableWG , deactivateWG , disableWG , reactivateWG) of
            (Just vpn  , Nothing  , False        , False     , False) -> activate vpn
            (Nothing   , Just vpn , False        , False     , False) -> enable vpn
            (Nothing   , Nothing  , True         , False     , False) -> deactivate
            (Nothing   , Nothing  , False        , True      , False) -> disable
            (Nothing   , Nothing  , False        , False     , True ) -> reactivate
            _                        -> return ()
  | otherwise = putStrLn "Options aside from --list or -l are mutually exclusive"
  where
    wgDir = "/etc/wireguard/"

    wgList :: IO [String]
    wgList = do
      rawlist <- getDirectoryContents wgDir
      let wgconf = filter (\f -> takeExtension f == ".conf") rawlist
      let wgs    = map (\f -> dropExtension f) wgconf
      return wgs
      
    wgStatus :: [String] -> IO [(String, String, String, Bool, Bool)]
    wgStatus wgs = do
      let quick = map (\w -> vpn2wg w) wgs
      let cmd_a   = ["is-active"]  <> quick
      let cmd_e   = ["is-enabled"] <> quick
      stats_a <- systemctl cmd_a
      stats_e <- systemctl cmd_e
      return $ [(wg
                , sact
                , sena
                , sact == "active"
                , sena == "enabled") | (wg, sact, sena) <- zip3 wgs stats_a stats_e ]

    formatStatus :: [(String, String, String, Bool, Bool)] -> String
    formatStatus wss = intercalate "\n" [w <> ": " <> sa <> " " <> se |(w, sa, se, _, _) <- wss]

    checkMutualExclusivity = check [ activateWG /= Nothing
                                   , enableWG   /= Nothing
                                   , deactivateWG
                                   , disableWG
                                   , reactivateWG]

    check bs   = (length $ filter id bs) `elem` [0, 1]
    vpn2wg vpn = "wg-quick@" <> vpn
    
    activate :: String -> IO ()
    activate vpn = do
      _ <- systemctl ["start", vpn2wg vpn]
      return ()

    enable :: String -> IO ()
    enable vpn = do
      _ <- systemctl ["enable", "--now", vpn2wg vpn]
      return ()
    
    deactivate :: IO ()
    deactivate   = do
      awgs <- activeWG
      mapM_ (\w -> systemctl $ ["stop"] <> [vpn2wg w]) awgs
      return ()

    disable :: IO ()
    disable = do
      awgs <- enabledWG
      mapM_ (\w -> systemctl $ ["disable", "--now"] <> [vpn2wg w]) awgs
      return ()


    reactivate :: IO ()
    reactivate   = do
      awgs <- activeWG
      mapM_ (\w -> systemctl $ ["restart"] <>  [vpn2wg w]) awgs
      return()

    activeWG :: IO [String]
    activeWG = do
      wgl <- wgList
      wgs <- wgStatus wgl
      return [s | (s, _, _, a, _) <- wgs, a]

    enabledWG :: IO [String]
    enabledWG = do
      wgl <- wgList
      wgs <- wgStatus wgl
      return [s | (s, _, _, _, e) <- wgs, e]