{-# LANGUAGE TypeFamilies #-}
module Propellor.Property.Tor where
import Propellor.Base
import qualified Propellor.Property.File as File
import qualified Propellor.Property.Apt as Apt
import qualified Propellor.Property.Service as Service
import qualified Propellor.Property.ConfFile as ConfFile
import Utility.DataUnits
import System.Posix.Files
import Data.Char
import Data.List
type HiddenServiceName = String
type NodeName = String
isBridge :: Property DebianLike
isBridge :: Property DebianLike
isBridge = [(String, String)] -> Property DebianLike
configured
[ ("BridgeRelay", "1")
, ("Exitpolicy", "reject *:*")
, ("ORPort", "443")
]
Property DebianLike -> String -> Property DebianLike
forall p. IsProp p => p -> String -> p
`describe` "tor bridge"
Property DebianLike
-> Property DebianLike
-> CombinedType (Property DebianLike) (Property DebianLike)
forall x y. Combines x y => x -> y -> CombinedType x y
`requires` Property DebianLike
server
isRelay :: Property DebianLike
isRelay :: Property DebianLike
isRelay = [(String, String)] -> Property DebianLike
configured
[ ("BridgeRelay", "0")
, ("Exitpolicy", "reject *:*")
, ("ORPort", "443")
]
Property DebianLike -> String -> Property DebianLike
forall p. IsProp p => p -> String -> p
`describe` "tor relay"
Property DebianLike
-> Property DebianLike
-> CombinedType (Property DebianLike) (Property DebianLike)
forall x y. Combines x y => x -> y -> CombinedType x y
`requires` Property DebianLike
server
named :: NodeName -> Property (HasInfo + DebianLike)
named :: String -> Property (HasInfo + DebianLike)
named n :: String
n = [(String, String)] -> Property DebianLike
configured [("Nickname", String
n')]
Property DebianLike -> String -> Property DebianLike
forall p. IsProp p => p -> String -> p
`describe` ("tor node named " String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
n')
Property DebianLike
-> Property
(MetaTypes
'[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish])
-> CombinedType
(Property DebianLike)
(Property
(MetaTypes
'[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish]))
forall x y. Combines x y => x -> y -> CombinedType x y
`requires` Context -> Property (HasInfo + DebianLike)
torPrivKey (String -> Context
Context ("tor " String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
n))
where
n' :: String
n' = String -> String
saneNickname String
n
torPrivKey :: Context -> Property (HasInfo + DebianLike)
torPrivKey :: Context -> Property (HasInfo + DebianLike)
torPrivKey context :: Context
context = [Property
(MetaTypes
'[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])]
-> Property
(MetaTypes
'[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
forall a. Monoid a => [a] -> a
mconcat ((String
-> Property
(MetaTypes
'[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]))
-> [String]
-> [Property
(MetaTypes
'[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])]
forall a b. (a -> b) -> [a] -> [b]
map String
-> CombinedType
(Property
(MetaTypes
'[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]))
(Property UnixLike)
String
-> Property
(MetaTypes
'[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
go [String]
keyfiles)
Property
(MetaTypes
'[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
-> Property DebianLike
-> CombinedType
(Property
(MetaTypes
'[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]))
(Property DebianLike)
forall x y. Combines x y => x -> y -> CombinedType x y
`onChange` Property DebianLike
restarted
Property
(MetaTypes
'[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish])
-> Property DebianLike
-> CombinedType
(Property
(MetaTypes
'[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish]))
(Property DebianLike)
forall x y. Combines x y => x -> y -> CombinedType x y
`requires` Property DebianLike
torPrivKeyDirExists
where
keyfiles :: [String]
keyfiles = (String -> String) -> [String] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map (String
torPrivKeyDir String -> String -> String
</>)
[ "secret_id_key"
, "ed25519_master_id_public_key"
, "ed25519_master_id_secret_key"
]
go :: String
-> CombinedType
(Property
(MetaTypes
'[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]))
(Property UnixLike)
go f :: String
f = String
f String -> Context -> Property (HasInfo + UnixLike)
forall c.
IsContext c =>
String -> c -> Property (HasInfo + UnixLike)
`File.hasPrivContent` Context
context
Property
(MetaTypes
'[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD])
-> Property UnixLike
-> CombinedType
(Property
(MetaTypes
'[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]))
(Property UnixLike)
forall x y. Combines x y => x -> y -> CombinedType x y
`onChange` String -> User -> Group -> Property UnixLike
File.ownerGroup String
f User
user (User -> Group
userGroup User
user)
torPrivKeyDirExists :: Property DebianLike
torPrivKeyDirExists :: Property DebianLike
torPrivKeyDirExists = String -> Property UnixLike
File.dirExists String
torPrivKeyDir
Property UnixLike
-> Property UnixLike
-> CombinedType (Property UnixLike) (Property UnixLike)
forall x y. Combines x y => x -> y -> CombinedType x y
`onChange` Property UnixLike
setperms
Property UnixLike
-> Property DebianLike
-> CombinedType (Property UnixLike) (Property DebianLike)
forall x y. Combines x y => x -> y -> CombinedType x y
`requires` Property DebianLike
installed
where
setperms :: CombinedType (Property UnixLike) (Property UnixLike)
setperms = String -> User -> Group -> Property UnixLike
File.ownerGroup String
torPrivKeyDir User
user (User -> Group
userGroup User
user)
Property UnixLike
-> Property UnixLike
-> CombinedType (Property UnixLike) (Property UnixLike)
forall x y. Combines x y => x -> y -> CombinedType x y
`before` String -> FileMode -> Property UnixLike
File.mode String
torPrivKeyDir 0O2700
torPrivKeyDir :: FilePath
torPrivKeyDir :: String
torPrivKeyDir = "/var/lib/tor/keys"
server :: Property DebianLike
server :: Property DebianLike
server = [(String, String)] -> Property DebianLike
configured [("SocksPort", "0")]
Property DebianLike
-> Property DebianLike
-> CombinedType (Property DebianLike) (Property DebianLike)
forall x y. Combines x y => x -> y -> CombinedType x y
`requires` Property DebianLike
installed
Property DebianLike
-> Property DebianLike
-> CombinedType (Property DebianLike) (Property DebianLike)
forall x y. Combines x y => x -> y -> CombinedType x y
`requires` [String] -> Property DebianLike
Apt.installed ["ntp"]
Property DebianLike -> String -> Property DebianLike
forall p. IsProp p => p -> String -> p
`describe` "tor server"
installed :: Property DebianLike
installed :: Property DebianLike
installed = [String] -> Property DebianLike
Apt.installed ["tor"]
configured :: [(String, String)] -> Property DebianLike
configured :: [(String, String)] -> Property DebianLike
configured settings :: [(String, String)]
settings = String -> ([String] -> [String]) -> String -> Property UnixLike
forall c.
(FileContent c, Eq c) =>
String -> (c -> c) -> String -> Property UnixLike
File.fileProperty "tor configured" [String] -> [String]
go String
mainConfig
Property UnixLike
-> Property DebianLike
-> CombinedType (Property UnixLike) (Property DebianLike)
forall x y. Combines x y => x -> y -> CombinedType x y
`onChange` Property DebianLike
restarted
where
ks :: [String]
ks = ((String, String) -> String) -> [(String, String)] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map (String, String) -> String
forall a b. (a, b) -> a
fst [(String, String)]
settings
go :: [String] -> [String]
go ls :: [String]
ls = [String] -> [String]
forall a. Ord a => [a] -> [a]
sort ([String] -> [String]) -> [String] -> [String]
forall a b. (a -> b) -> a -> b
$ ((String, String) -> String) -> [(String, String)] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map (String, String) -> String
toconfig ([(String, String)] -> [String]) -> [(String, String)] -> [String]
forall a b. (a -> b) -> a -> b
$
((String, String) -> Bool)
-> [(String, String)] -> [(String, String)]
forall a. (a -> Bool) -> [a] -> [a]
filter (\(k :: String
k, _) -> String
k String -> [String] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`notElem` [String]
ks) ((String -> (String, String)) -> [String] -> [(String, String)]
forall a b. (a -> b) -> [a] -> [b]
map String -> (String, String)
fromconfig [String]
ls)
[(String, String)] -> [(String, String)] -> [(String, String)]
forall a. [a] -> [a] -> [a]
++ [(String, String)]
settings
toconfig :: (String, String) -> String
toconfig (k :: String
k, v :: String
v) = String
k String -> String -> String
forall a. [a] -> [a] -> [a]
++ " " String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
v
fromconfig :: String -> (String, String)
fromconfig = (Char -> Bool) -> String -> (String, String)
forall a. (a -> Bool) -> [a] -> ([a], [a])
separate (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== ' ')
data BwLimit
= PerSecond String
| PerDay String
| PerMonth String
bandwidthRate :: BwLimit -> Property DebianLike
bandwidthRate :: BwLimit -> Property DebianLike
bandwidthRate (PerSecond s :: String
s) = String -> Integer -> Property DebianLike
bandwidthRate' String
s 1
bandwidthRate (PerDay s :: String
s) = String -> Integer -> Property DebianLike
bandwidthRate' String
s (24Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
*60Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
*60)
bandwidthRate (PerMonth s :: String
s) = String -> Integer -> Property DebianLike
bandwidthRate' String
s (31Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
*24Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
*60Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
*60)
bandwidthRate' :: String -> Integer -> Property DebianLike
bandwidthRate' :: String -> Integer -> Property DebianLike
bandwidthRate' s :: String
s divby :: Integer
divby = case [Unit] -> String -> Maybe Integer
readSize [Unit]
dataUnits String
s of
Just sz :: Integer
sz -> let v :: String
v = Integer -> String
forall a. Show a => a -> String
show (Integer
sz Integer -> Integer -> Integer
forall a. Integral a => a -> a -> a
`div` Integer
divby) String -> String -> String
forall a. [a] -> [a] -> [a]
++ " bytes"
in [(String, String)] -> Property DebianLike
configured [("BandwidthRate", String
v)]
Property DebianLike -> String -> Property DebianLike
forall p. IsProp p => p -> String -> p
`describe` ("tor BandwidthRate " String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
v)
Nothing -> String -> Propellor Result -> Property DebianLike
forall k (metatypes :: k).
SingI metatypes =>
String -> Propellor Result -> Property (MetaTypes metatypes)
property ("unable to parse " String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
s) Propellor Result
noChange
hiddenService :: HiddenServiceName -> Port -> Property DebianLike
hiddenService :: String -> Port -> Property DebianLike
hiddenService hn :: String
hn port :: Port
port = String -> [Port] -> Property DebianLike
hiddenService' String
hn [Port
port]
hiddenService' :: HiddenServiceName -> [Port] -> Property DebianLike
hiddenService' :: String -> [Port] -> Property DebianLike
hiddenService' hn :: String
hn ports :: [Port]
ports = String
-> SectionStart
-> SectionStart
-> ([String] -> [String])
-> ([String] -> [String])
-> String
-> Property UnixLike
ConfFile.adjustSection
([String] -> String
unwords ["hidden service", String
hn, "available on ports", String -> [String] -> String
forall a. [a] -> [[a]] -> [a]
intercalate "," ((Port -> String) -> [Port] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map Port -> String
forall t. ConfigurableValue t => t -> String
val [Port]
ports')])
(String -> SectionStart
forall a. Eq a => a -> a -> Bool
== String
oniondir)
(Bool -> Bool
not (Bool -> Bool) -> SectionStart -> SectionStart
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> SectionStart
forall a. Eq a => [a] -> [a] -> Bool
isPrefixOf "HiddenServicePort")
([String] -> [String] -> [String]
forall a b. a -> b -> a
const (String
oniondir String -> [String] -> [String]
forall a. a -> [a] -> [a]
: [String]
onionports))
([String] -> [String] -> [String]
forall a. [a] -> [a] -> [a]
++ String
oniondir String -> [String] -> [String]
forall a. a -> [a] -> [a]
: [String]
onionports)
String
mainConfig
Property UnixLike
-> Property DebianLike
-> CombinedType (Property UnixLike) (Property DebianLike)
forall x y. Combines x y => x -> y -> CombinedType x y
`onChange` Property DebianLike
restarted
where
oniondir :: String
oniondir = [String] -> String
unwords ["HiddenServiceDir", String
varLib String -> String -> String
</> String
hn]
onionports :: [String]
onionports = (Port -> String) -> [Port] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map Port -> String
forall t. ConfigurableValue t => t -> String
onionport [Port]
ports'
ports' :: [Port]
ports' = [Port] -> [Port]
forall a. Ord a => [a] -> [a]
sort [Port]
ports
onionport :: t -> String
onionport port :: t
port = [String] -> String
unwords ["HiddenServicePort", t -> String
forall t. ConfigurableValue t => t -> String
val t
port, "127.0.0.1:" String -> String -> String
forall a. [a] -> [a] -> [a]
++ t -> String
forall t. ConfigurableValue t => t -> String
val t
port]
hiddenServiceAvailable :: HiddenServiceName -> Port -> Property DebianLike
hiddenServiceAvailable :: String -> Port -> Property DebianLike
hiddenServiceAvailable hn :: String
hn port :: Port
port = String -> [Port] -> Property DebianLike
hiddenServiceAvailable' String
hn [Port
port]
hiddenServiceAvailable' :: HiddenServiceName -> [Port] -> Property DebianLike
hiddenServiceAvailable' :: String -> [Port] -> Property DebianLike
hiddenServiceAvailable' hn :: String
hn ports :: [Port]
ports = Property DebianLike -> Property DebianLike
hiddenServiceHostName (Property DebianLike -> Property DebianLike)
-> Property DebianLike -> Property DebianLike
forall a b. (a -> b) -> a -> b
$ String -> [Port] -> Property DebianLike
hiddenService' String
hn [Port]
ports
where
hiddenServiceHostName :: Property DebianLike -> Property DebianLike
hiddenServiceHostName p :: Property DebianLike
p = Property DebianLike
-> (Propellor Result -> Propellor Result) -> Property DebianLike
forall metatypes.
Property metatypes
-> (Propellor Result -> Propellor Result) -> Property metatypes
adjustPropertySatisfy Property DebianLike
p ((Propellor Result -> Propellor Result) -> Property DebianLike)
-> (Propellor Result -> Propellor Result) -> Property DebianLike
forall a b. (a -> b) -> a -> b
$ \satisfy :: Propellor Result
satisfy -> do
Result
r <- Propellor Result
satisfy
Either IOException String
mh <- IO (Either IOException String)
-> Propellor (Either IOException String)
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO (Either IOException String)
-> Propellor (Either IOException String))
-> IO (Either IOException String)
-> Propellor (Either IOException String)
forall a b. (a -> b) -> a -> b
$ IO String -> IO (Either IOException String)
forall (m :: * -> *) a.
MonadCatch m =>
m a -> m (Either IOException a)
tryIO (IO String -> IO (Either IOException String))
-> IO String -> IO (Either IOException String)
forall a b. (a -> b) -> a -> b
$ String -> IO String
readFile (String
varLib String -> String -> String
</> String
hn String -> String -> String
</> "hostname")
case Either IOException String
mh of
Right h :: String
h -> [String] -> Propellor ()
forall (m :: * -> *). MonadIO m => [String] -> m ()
infoMessage ["hidden service hostname:", String
h]
Left _e :: IOException
_e -> String -> Propellor ()
forall (m :: * -> *). MonadIO m => String -> m ()
warningMessage "hidden service hostname not available yet"
Result -> Propellor Result
forall (m :: * -> *) a. Monad m => a -> m a
return Result
r
hiddenServiceData :: IsContext c => HiddenServiceName -> c -> Property (HasInfo + DebianLike)
hiddenServiceData :: String -> c -> Property (HasInfo + DebianLike)
hiddenServiceData hn :: String
hn context :: c
context = String
-> Props
(MetaTypes
'[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish])
-> Property
(MetaTypes
'[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish])
forall k (metatypes :: k).
SingI metatypes =>
String
-> Props (MetaTypes metatypes) -> Property (MetaTypes metatypes)
combineProperties String
desc (Props
(MetaTypes
'[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish])
-> Property (HasInfo + DebianLike))
-> Props
(MetaTypes
'[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish])
-> Property (HasInfo + DebianLike)
forall a b. (a -> b) -> a -> b
$ Props UnixLike
props
Props UnixLike
-> Property
(MetaTypes
'[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish])
-> Props
(MetaTypes
(Combine
'[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]
'[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish]))
forall a p (y :: [a]) (x :: [a]).
(IsProp p, MetaTypes y ~ GetMetaTypes p,
CheckCombinableNote x y (NoteFor ('Text "&"))) =>
Props (MetaTypes x) -> p -> Props (MetaTypes (Combine x y))
& String -> Property (HasInfo + DebianLike)
installonion "hostname"
Props
(MetaTypes
'[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish])
-> Property
(MetaTypes
'[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish])
-> Props
(MetaTypes
(Combine
'[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish]
'[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish]))
forall a p (y :: [a]) (x :: [a]).
(IsProp p, MetaTypes y ~ GetMetaTypes p,
CheckCombinableNote x y (NoteFor ('Text "&"))) =>
Props (MetaTypes x) -> p -> Props (MetaTypes (Combine x y))
& String -> Property (HasInfo + DebianLike)
installonion "private_key"
where
desc :: String
desc = [String] -> String
unwords ["hidden service data available in", String
varLib String -> String -> String
</> String
hn]
installonion :: FilePath -> Property (HasInfo + DebianLike)
installonion :: String -> Property (HasInfo + DebianLike)
installonion basef :: String
basef =
let f :: String
f = String
varLib String -> String -> String
</> String
hn String -> String -> String
</> String
basef
in PrivDataField
-> c
-> (((PrivData -> Propellor Result) -> Propellor Result)
-> Property
(MetaTypes
'[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish]))
-> Property
(MetaTypes
'[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish])
forall c s metatypes.
(IsContext c, IsPrivDataSource s,
IncludesInfo metatypes ~ 'True) =>
s
-> c
-> (((PrivData -> Propellor Result) -> Propellor Result)
-> Property metatypes)
-> Property metatypes
withPrivData (String -> PrivDataField
PrivFile String
f) c
context ((((PrivData -> Propellor Result) -> Propellor Result)
-> Property
(MetaTypes
'[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish]))
-> Property (HasInfo + DebianLike))
-> (((PrivData -> Propellor Result) -> Propellor Result)
-> Property
(MetaTypes
'[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish]))
-> Property (HasInfo + DebianLike)
forall a b. (a -> b) -> a -> b
$ \getcontent :: (PrivData -> Propellor Result) -> Propellor Result
getcontent ->
String
-> (OuterMetaTypesWitness
'[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish]
-> Propellor Result)
-> Property
(MetaTypes
'[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish])
forall k (metatypes :: k).
SingI metatypes =>
String
-> (OuterMetaTypesWitness metatypes -> Propellor Result)
-> Property (MetaTypes metatypes)
property' String
desc ((OuterMetaTypesWitness
'[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish]
-> Propellor Result)
-> Property
(MetaTypes
'[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish]))
-> (OuterMetaTypesWitness
'[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish]
-> Propellor Result)
-> Property
(MetaTypes
'[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish])
forall a b. (a -> b) -> a -> b
$ \w :: OuterMetaTypesWitness
'[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish]
w -> (PrivData -> Propellor Result) -> Propellor Result
getcontent ((PrivData -> Propellor Result) -> Propellor Result)
-> (PrivData -> Propellor Result) -> Propellor Result
forall a b. (a -> b) -> a -> b
$ \privcontent :: PrivData
privcontent ->
Propellor Bool
-> (Propellor Result, Propellor Result) -> Propellor Result
forall (m :: * -> *) a. Monad m => m Bool -> (m a, m a) -> m a
ifM (IO Bool -> Propellor Bool
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO Bool -> Propellor Bool) -> IO Bool -> Propellor Bool
forall a b. (a -> b) -> a -> b
$ String -> IO Bool
doesFileExist String
f)
( Propellor Result
noChange
, OuterMetaTypesWitness
'[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish]
-> Property UnixLike -> Propellor Result
forall (inner :: [MetaType]) (outer :: [MetaType]).
EnsurePropertyAllowed inner outer =>
OuterMetaTypesWitness outer
-> Property (MetaTypes inner) -> Propellor Result
ensureProperty OuterMetaTypesWitness
'[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish]
w (Property UnixLike -> Propellor Result)
-> Property UnixLike -> Propellor Result
forall a b. (a -> b) -> a -> b
$ String -> Props UnixLike -> Property UnixLike
forall k (metatypes :: k).
SingI metatypes =>
String
-> Props (MetaTypes metatypes) -> Property (MetaTypes metatypes)
propertyList String
desc (Props UnixLike -> Property UnixLike)
-> Props UnixLike -> Property UnixLike
forall a b. (a -> b) -> a -> b
$ [Property UnixLike] -> Props UnixLike
forall k (metatypes :: k).
[Property (MetaTypes metatypes)] -> Props (MetaTypes metatypes)
toProps
[ String -> Propellor Result -> Property UnixLike
forall k (metatypes :: k).
SingI metatypes =>
String -> Propellor Result -> Property (MetaTypes metatypes)
property String
desc (Propellor Result -> Property UnixLike)
-> Propellor Result -> Property UnixLike
forall a b. (a -> b) -> a -> b
$ IO () -> Propellor Result
makeChange (IO () -> Propellor Result) -> IO () -> Propellor Result
forall a b. (a -> b) -> a -> b
$ do
Bool -> String -> IO ()
createDirectoryIfMissing Bool
True (String -> String
takeDirectory String
f)
String -> String -> IO ()
writeFileProtected String
f ([String] -> String
unlines (PrivData -> [String]
privDataLines PrivData
privcontent))
, String -> FileMode -> Property UnixLike
File.mode (String -> String
takeDirectory String
f) (FileMode -> Property UnixLike) -> FileMode -> Property UnixLike
forall a b. (a -> b) -> a -> b
$ [FileMode] -> FileMode
combineModes
[FileMode
ownerReadMode, FileMode
ownerWriteMode, FileMode
ownerExecuteMode]
, String -> User -> Group -> Property UnixLike
File.ownerGroup (String -> String
takeDirectory String
f) User
user (User -> Group
userGroup User
user)
, String -> User -> Group -> Property UnixLike
File.ownerGroup String
f User
user (User -> Group
userGroup User
user)
]
)
restarted :: Property DebianLike
restarted :: Property DebianLike
restarted = String -> Property DebianLike
Service.restarted "tor"
mainConfig :: FilePath
mainConfig :: String
mainConfig = "/etc/tor/torrc"
varLib :: FilePath
varLib :: String
varLib = "/var/lib/tor"
varRun :: FilePath
varRun :: String
varRun = "/var/run/tor"
user :: User
user :: User
user = String -> User
User "debian-tor"
type NickName = String
saneNickname :: String -> NickName
saneNickname :: String -> String
saneNickname s :: String
s
| SectionStart
forall (t :: * -> *) a. Foldable t => t a -> Bool
null String
n = "unnamed"
| Bool
otherwise = String
n
where
legal :: Char -> Bool
legal c :: Char
c = Char -> Bool
isNumber Char
c Bool -> Bool -> Bool
|| Char -> Bool
isAsciiUpper Char
c Bool -> Bool -> Bool
|| Char -> Bool
isAsciiLower Char
c
n :: String
n = Int -> String -> String
forall a. Int -> [a] -> [a]
take 19 (String -> String) -> String -> String
forall a b. (a -> b) -> a -> b
$ (Char -> Bool) -> String -> String
forall a. (a -> Bool) -> [a] -> [a]
filter Char -> Bool
legal String
s