{-# 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
[ (String
"BridgeRelay", String
"1")
, (String
"Exitpolicy", String
"reject *:*")
, (String
"ORPort", String
"443")
]
Property DebianLike -> String -> Property DebianLike
forall p. IsProp p => p -> String -> p
`describe` String
"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
[ (String
"BridgeRelay", String
"0")
, (String
"Exitpolicy", String
"reject *:*")
, (String
"ORPort", String
"443")
]
Property DebianLike -> String -> Property DebianLike
forall p. IsProp p => p -> String -> p
`describe` String
"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 String
n = [(String, String)] -> Property DebianLike
configured [(String
"Nickname", String
n')]
Property DebianLike -> String -> Property DebianLike
forall p. IsProp p => p -> String -> p
`describe` (String
"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 (String
"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 = [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
</>)
[ String
"secret_id_key"
, String
"ed25519_master_id_public_key"
, String
"ed25519_master_id_secret_key"
]
go :: String
-> CombinedType
(Property
(MetaTypes
'[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]))
(Property UnixLike)
go 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 FileMode
0O2700
torPrivKeyDir :: FilePath
torPrivKeyDir :: String
torPrivKeyDir = String
"/var/lib/tor/keys"
server :: Property DebianLike
server :: Property DebianLike
server = [(String, String)] -> Property DebianLike
configured [(String
"SocksPort", String
"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 [String
"ntp"]
Property DebianLike -> String -> Property DebianLike
forall p. IsProp p => p -> String -> p
`describe` String
"tor server"
installed :: Property DebianLike
installed :: Property DebianLike
installed = [String] -> Property DebianLike
Apt.installed [String
"tor"]
configured :: [(String, String)] -> Property DebianLike
configured :: [(String, String)] -> Property DebianLike
configured [(String, String)]
settings = String -> ([String] -> [String]) -> String -> Property UnixLike
forall c.
(FileContent c, Eq c) =>
String -> (c -> c) -> String -> Property UnixLike
File.fileProperty String
"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 [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 (\(String
k, String
_) -> 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 (String
k, String
v) = String
k String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
" " 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
== Char
' ')
data BwLimit
= PerSecond String
| PerDay String
| PerMonth String
bandwidthRate :: BwLimit -> Property DebianLike
bandwidthRate :: BwLimit -> Property DebianLike
bandwidthRate (PerSecond String
s) = String -> Integer -> Property DebianLike
bandwidthRate' String
s Integer
1
bandwidthRate (PerDay String
s) = String -> Integer -> Property DebianLike
bandwidthRate' String
s (Integer
24Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
*Integer
60Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
*Integer
60)
bandwidthRate (PerMonth String
s) = String -> Integer -> Property DebianLike
bandwidthRate' String
s (Integer
31Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
*Integer
24Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
*Integer
60Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
*Integer
60)
bandwidthRate' :: String -> Integer -> Property DebianLike
bandwidthRate' :: String -> Integer -> Property DebianLike
bandwidthRate' String
s Integer
divby = case [Unit] -> String -> Maybe Integer
readSize [Unit]
dataUnits String
s of
Just 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]
++ String
" bytes"
in [(String, String)] -> Property DebianLike
configured [(String
"BandwidthRate", String
v)]
Property DebianLike -> String -> Property DebianLike
forall p. IsProp p => p -> String -> p
`describe` (String
"tor BandwidthRate " String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
v)
Maybe Integer
Nothing -> String -> Propellor Result -> Property DebianLike
forall k (metatypes :: k).
SingI metatypes =>
String -> Propellor Result -> Property (MetaTypes metatypes)
property (String
"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 String
hn Port
port = String -> [Port] -> Property DebianLike
hiddenService' String
hn [Port
port]
hiddenService' :: HiddenServiceName -> [Port] -> Property DebianLike
hiddenService' :: String -> [Port] -> Property DebianLike
hiddenService' String
hn [Port]
ports = String
-> SectionStart
-> SectionStart
-> ([String] -> [String])
-> ([String] -> [String])
-> String
-> Property UnixLike
ConfFile.adjustSection
([String] -> String
unwords [String
"hidden service", String
hn, String
"available on ports", String -> [String] -> String
forall a. [a] -> [[a]] -> [a]
intercalate String
"," ((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 String
"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 [String
"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 t
port = [String] -> String
unwords [String
"HiddenServicePort", t -> String
forall t. ConfigurableValue t => t -> String
val t
port, String
"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 String
hn Port
port = String -> [Port] -> Property DebianLike
hiddenServiceAvailable' String
hn [Port
port]
hiddenServiceAvailable' :: HiddenServiceName -> [Port] -> Property DebianLike
hiddenServiceAvailable' :: String -> [Port] -> Property DebianLike
hiddenServiceAvailable' String
hn [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 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
$ \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
</> String
"hostname")
case Either IOException String
mh of
Right String
h -> [String] -> Propellor ()
forall (m :: * -> *). MonadIO m => [String] -> m ()
infoMessage [String
"hidden service hostname:", String
h]
Left IOException
_e -> String -> Propellor ()
forall (m :: * -> *). MonadIO m => String -> m ()
warningMessage String
"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 String
hn 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
(MetaTypes
'[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish]))
-> Props
(MetaTypes
'[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish])
-> Property
(MetaTypes
'[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish])
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 String
"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 String
"private_key"
where
desc :: String
desc = [String] -> String
unwords [String
"hidden service data available in", String
varLib String -> String -> String
</> String
hn]
installonion :: FilePath -> Property (HasInfo + DebianLike)
installonion :: String -> Property (HasInfo + DebianLike)
installonion 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
(MetaTypes
'[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish]))
-> (((PrivData -> Propellor Result) -> Propellor Result)
-> Property
(MetaTypes
'[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish]))
-> Property
(MetaTypes
'[ 'WithInfo, 'Targeting 'OSDebian, 'Targeting 'OSBuntish])
forall a b. (a -> b) -> a -> b
$ \(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
$ \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
$ \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 String
"tor"
mainConfig :: FilePath
mainConfig :: String
mainConfig = String
"/etc/tor/torrc"
varLib :: FilePath
varLib :: String
varLib = String
"/var/lib/tor"
varRun :: FilePath
varRun :: String
varRun = String
"/var/run/tor"
user :: User
user :: User
user = String -> User
User String
"debian-tor"
type NickName = String
saneNickname :: String -> NickName
saneNickname :: String -> String
saneNickname String
s
| SectionStart
forall (t :: * -> *) a. Foldable t => t a -> Bool
null String
n = String
"unnamed"
| Bool
otherwise = String
n
where
legal :: Char -> Bool
legal 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 Int
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