{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE OverloadedStrings #-}

-- This file is part of the Wire Server implementation.
--
-- Copyright (C) 2022 Wire Swiss GmbH <opensource@wire.com>
--
-- This program is free software: you can redistribute it and/or modify it under
-- the terms of the GNU Affero General Public License as published by the Free
-- Software Foundation, either version 3 of the License, or (at your option) any
-- later version.
--
-- This program is distributed in the hope that it will be useful, but WITHOUT
-- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
-- FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
-- details.
--
-- You should have received a copy of the GNU Affero General Public License along
-- with this program. If not, see <https://www.gnu.org/licenses/>.

module Data.ZAuth.Creation
  ( -- * Types
    Create,
    Env,

    -- * Initialisation
    mkEnv,
    runCreate,

    -- * Specific
    accessToken,
    accessToken1,
    userToken,
    sessionToken,
    botToken,
    providerToken,
    legalHoldAccessToken,
    legalHoldAccessToken1,
    legalHoldUserToken,

    -- * Generic
    newToken,
    renewToken,
  )
where

import Control.Lens
import Control.Monad.Catch (MonadCatch, MonadThrow)
import Data.ByteString qualified as Strict
import Data.ByteString.Builder (toLazyByteString)
import Data.ByteString.Conversion
import Data.ByteString.Lazy (toStrict)
import Data.Time.Clock.POSIX
import Data.UUID
import Data.Vector (Vector, (!))
import Data.Vector qualified as Vec
import Data.ZAuth.Token hiding (signature)
import Imports
import Sodium.Crypto.Sign
import System.Random.MWC

data Env = Env
  { Env -> Int
keyIdx :: Int,
    Env -> Vector (ByteString -> IO Signature)
zSign :: Vector (Strict.ByteString -> IO Signature),
    Env -> GenIO
randGen :: GenIO
  }

newtype Create a = Create
  { forall a. Create a -> ReaderT Env IO a
zauth :: ReaderT Env IO a
  }
  deriving
    ( (forall a b. (a -> b) -> Create a -> Create b)
-> (forall a b. a -> Create b -> Create a) -> Functor Create
forall a b. a -> Create b -> Create a
forall a b. (a -> b) -> Create a -> Create b
forall (f :: * -> *).
(forall a b. (a -> b) -> f a -> f b)
-> (forall a b. a -> f b -> f a) -> Functor f
$cfmap :: forall a b. (a -> b) -> Create a -> Create b
fmap :: forall a b. (a -> b) -> Create a -> Create b
$c<$ :: forall a b. a -> Create b -> Create a
<$ :: forall a b. a -> Create b -> Create a
Functor,
      Functor Create
Functor Create =>
(forall a. a -> Create a)
-> (forall a b. Create (a -> b) -> Create a -> Create b)
-> (forall a b c.
    (a -> b -> c) -> Create a -> Create b -> Create c)
-> (forall a b. Create a -> Create b -> Create b)
-> (forall a b. Create a -> Create b -> Create a)
-> Applicative Create
forall a. a -> Create a
forall a b. Create a -> Create b -> Create a
forall a b. Create a -> Create b -> Create b
forall a b. Create (a -> b) -> Create a -> Create b
forall a b c. (a -> b -> c) -> Create a -> Create b -> Create c
forall (f :: * -> *).
Functor f =>
(forall a. a -> f a)
-> (forall a b. f (a -> b) -> f a -> f b)
-> (forall a b c. (a -> b -> c) -> f a -> f b -> f c)
-> (forall a b. f a -> f b -> f b)
-> (forall a b. f a -> f b -> f a)
-> Applicative f
$cpure :: forall a. a -> Create a
pure :: forall a. a -> Create a
$c<*> :: forall a b. Create (a -> b) -> Create a -> Create b
<*> :: forall a b. Create (a -> b) -> Create a -> Create b
$cliftA2 :: forall a b c. (a -> b -> c) -> Create a -> Create b -> Create c
liftA2 :: forall a b c. (a -> b -> c) -> Create a -> Create b -> Create c
$c*> :: forall a b. Create a -> Create b -> Create b
*> :: forall a b. Create a -> Create b -> Create b
$c<* :: forall a b. Create a -> Create b -> Create a
<* :: forall a b. Create a -> Create b -> Create a
Applicative,
      Applicative Create
Applicative Create =>
(forall a b. Create a -> (a -> Create b) -> Create b)
-> (forall a b. Create a -> Create b -> Create b)
-> (forall a. a -> Create a)
-> Monad Create
forall a. a -> Create a
forall a b. Create a -> Create b -> Create b
forall a b. Create a -> (a -> Create b) -> Create b
forall (m :: * -> *).
Applicative m =>
(forall a b. m a -> (a -> m b) -> m b)
-> (forall a b. m a -> m b -> m b)
-> (forall a. a -> m a)
-> Monad m
$c>>= :: forall a b. Create a -> (a -> Create b) -> Create b
>>= :: forall a b. Create a -> (a -> Create b) -> Create b
$c>> :: forall a b. Create a -> Create b -> Create b
>> :: forall a b. Create a -> Create b -> Create b
$creturn :: forall a. a -> Create a
return :: forall a. a -> Create a
Monad,
      Monad Create
Monad Create => (forall a. IO a -> Create a) -> MonadIO Create
forall a. IO a -> Create a
forall (m :: * -> *).
Monad m =>
(forall a. IO a -> m a) -> MonadIO m
$cliftIO :: forall a. IO a -> Create a
liftIO :: forall a. IO a -> Create a
MonadIO,
      Monad Create
Monad Create =>
(forall e a. (HasCallStack, Exception e) => e -> Create a)
-> MonadThrow Create
forall e a. (HasCallStack, Exception e) => e -> Create a
forall (m :: * -> *).
Monad m =>
(forall e a. (HasCallStack, Exception e) => e -> m a)
-> MonadThrow m
$cthrowM :: forall e a. (HasCallStack, Exception e) => e -> Create a
throwM :: forall e a. (HasCallStack, Exception e) => e -> Create a
MonadThrow,
      MonadThrow Create
MonadThrow Create =>
(forall e a.
 (HasCallStack, Exception e) =>
 Create a -> (e -> Create a) -> Create a)
-> MonadCatch Create
forall e a.
(HasCallStack, Exception e) =>
Create a -> (e -> Create a) -> Create a
forall (m :: * -> *).
MonadThrow m =>
(forall e a.
 (HasCallStack, Exception e) =>
 m a -> (e -> m a) -> m a)
-> MonadCatch m
$ccatch :: forall e a.
(HasCallStack, Exception e) =>
Create a -> (e -> Create a) -> Create a
catch :: forall e a.
(HasCallStack, Exception e) =>
Create a -> (e -> Create a) -> Create a
MonadCatch
    )

tokenVersion :: Int
tokenVersion :: Int
tokenVersion = Int
1

mkEnv :: SecretKey -> [SecretKey] -> IO Env
mkEnv :: SecretKey -> [SecretKey] -> IO Env
mkEnv SecretKey
k [SecretKey]
kk = Int -> Vector (ByteString -> IO Signature) -> GenIO -> Env
Env Int
1 ([ByteString -> IO Signature] -> Vector (ByteString -> IO Signature)
forall a. [a] -> Vector a
Vec.fromList ([ByteString -> IO Signature]
 -> Vector (ByteString -> IO Signature))
-> [ByteString -> IO Signature]
-> Vector (ByteString -> IO Signature)
forall a b. (a -> b) -> a -> b
$ (SecretKey -> ByteString -> IO Signature)
-> [SecretKey] -> [ByteString -> IO Signature]
forall a b. (a -> b) -> [a] -> [b]
map SecretKey -> ByteString -> IO Signature
signature (SecretKey
k SecretKey -> [SecretKey] -> [SecretKey]
forall a. a -> [a] -> [a]
: [SecretKey]
kk)) (Gen RealWorld -> Env) -> IO (Gen RealWorld) -> IO Env
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> IO (Gen RealWorld) -> IO (Gen RealWorld)
forall a. IO a -> IO a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO IO (Gen RealWorld)
IO GenIO
createSystemRandom

runCreate :: Env -> Int -> Create a -> IO a
runCreate :: forall a. Env -> Int -> Create a -> IO a
runCreate Env
z Int
k Create a
m = do
  Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Int
k Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
1 Bool -> Bool -> Bool
|| Int
k Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Vector (ByteString -> IO Signature) -> Int
forall a. Vector a -> Int
Vec.length (Env -> Vector (ByteString -> IO Signature)
zSign Env
z)) (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$
    [Char] -> IO ()
forall a. HasCallStack => [Char] -> a
error [Char]
"runCreate: Key index out of range."
  ReaderT Env IO a -> Env -> IO a
forall r (m :: * -> *) a. ReaderT r m a -> r -> m a
runReaderT (Create a -> ReaderT Env IO a
forall a. Create a -> ReaderT Env IO a
zauth Create a
m) (Env
z {keyIdx = k})

userToken :: Integer -> UUID -> Maybe Text -> Word32 -> Create (Token User)
userToken :: Integer -> UUID -> Maybe Text -> Word32 -> Create (Token User)
userToken Integer
dur UUID
usr Maybe Text
cli Word32
rnd = do
  POSIXTime
d <- Integer -> Create POSIXTime
forall (m :: * -> *). MonadIO m => Integer -> m POSIXTime
expiry Integer
dur
  POSIXTime -> Type -> Maybe Tag -> User -> Create (Token User)
forall a.
ToByteString a =>
POSIXTime -> Type -> Maybe Tag -> a -> Create (Token a)
newToken POSIXTime
d Type
U Maybe Tag
forall a. Maybe a
Nothing (UUID -> Maybe Text -> Word32 -> User
mkUser UUID
usr Maybe Text
cli Word32
rnd)

sessionToken :: Integer -> UUID -> Maybe Text -> Word32 -> Create (Token User)
sessionToken :: Integer -> UUID -> Maybe Text -> Word32 -> Create (Token User)
sessionToken Integer
dur UUID
usr Maybe Text
cli Word32
rnd = do
  POSIXTime
d <- Integer -> Create POSIXTime
forall (m :: * -> *). MonadIO m => Integer -> m POSIXTime
expiry Integer
dur
  POSIXTime -> Type -> Maybe Tag -> User -> Create (Token User)
forall a.
ToByteString a =>
POSIXTime -> Type -> Maybe Tag -> a -> Create (Token a)
newToken POSIXTime
d Type
U (Tag -> Maybe Tag
forall a. a -> Maybe a
Just Tag
S) (UUID -> Maybe Text -> Word32 -> User
mkUser UUID
usr Maybe Text
cli Word32
rnd)

-- | Create an access token taking a duration, userId, clientId and a (random)
-- number that can be used as connection identifier
accessToken :: Integer -> UUID -> Maybe Text -> Word64 -> Create (Token Access)
accessToken :: Integer -> UUID -> Maybe Text -> Word64 -> Create (Token Access)
accessToken Integer
dur UUID
usr Maybe Text
cid Word64
con = do
  POSIXTime
d <- Integer -> Create POSIXTime
forall (m :: * -> *). MonadIO m => Integer -> m POSIXTime
expiry Integer
dur
  POSIXTime -> Type -> Maybe Tag -> Access -> Create (Token Access)
forall a.
ToByteString a =>
POSIXTime -> Type -> Maybe Tag -> a -> Create (Token a)
newToken POSIXTime
d Type
A Maybe Tag
forall a. Maybe a
Nothing (UUID -> Maybe Text -> Word64 -> Access
mkAccess UUID
usr Maybe Text
cid Word64
con)

-- | Create an access token taking a duration, userId and clientId.
-- Similar to 'accessToken', except that the connection identifier is randomly
-- generated.
accessToken1 :: Integer -> UUID -> Maybe Text -> Create (Token Access)
accessToken1 :: Integer -> UUID -> Maybe Text -> Create (Token Access)
accessToken1 Integer
dur UUID
usr Maybe Text
cid = do
  Gen RealWorld
g <- ReaderT Env IO (Gen RealWorld) -> Create (Gen RealWorld)
forall a. ReaderT Env IO a -> Create a
Create (ReaderT Env IO (Gen RealWorld) -> Create (Gen RealWorld))
-> ReaderT Env IO (Gen RealWorld) -> Create (Gen RealWorld)
forall a b. (a -> b) -> a -> b
$ (Env -> Gen RealWorld) -> ReaderT Env IO (Gen RealWorld)
forall r (m :: * -> *) a. MonadReader r m => (r -> a) -> m a
asks Env -> Gen RealWorld
Env -> GenIO
randGen
  Word64
d <- IO Word64 -> Create Word64
forall a. IO a -> Create a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO Word64 -> Create Word64) -> IO Word64 -> Create Word64
forall a b. (a -> b) -> a -> b
$ (GenIO -> IO Word64) -> GenIO -> IO Word64
forall a. (GenIO -> IO a) -> GenIO -> IO a
asGenIO (GenIO -> IO Word64
forall a (m :: * -> *).
(Variate a, PrimMonad m) =>
Gen (PrimState m) -> m a
forall (m :: * -> *). PrimMonad m => Gen (PrimState m) -> m Word64
uniform :: GenIO -> IO Word64) Gen RealWorld
GenIO
g
  Integer -> UUID -> Maybe Text -> Word64 -> Create (Token Access)
accessToken Integer
dur UUID
usr Maybe Text
cid Word64
d

legalHoldUserToken :: Integer -> UUID -> Maybe Text -> Word32 -> Create (Token LegalHoldUser)
legalHoldUserToken :: Integer
-> UUID -> Maybe Text -> Word32 -> Create (Token LegalHoldUser)
legalHoldUserToken Integer
dur UUID
usr Maybe Text
cli Word32
rnd = do
  POSIXTime
d <- Integer -> Create POSIXTime
forall (m :: * -> *). MonadIO m => Integer -> m POSIXTime
expiry Integer
dur
  POSIXTime
-> Type
-> Maybe Tag
-> LegalHoldUser
-> Create (Token LegalHoldUser)
forall a.
ToByteString a =>
POSIXTime -> Type -> Maybe Tag -> a -> Create (Token a)
newToken POSIXTime
d Type
LU Maybe Tag
forall a. Maybe a
Nothing (UUID -> Maybe Text -> Word32 -> LegalHoldUser
mkLegalHoldUser UUID
usr Maybe Text
cli Word32
rnd)

-- | Create a legal hold access token taking a duration, userId, clientId and a
-- (random) number that can be used as connection identifier
legalHoldAccessToken ::
  Integer ->
  UUID ->
  Maybe Text ->
  Word64 ->
  Create (Token LegalHoldAccess)
legalHoldAccessToken :: Integer
-> UUID -> Maybe Text -> Word64 -> Create (Token LegalHoldAccess)
legalHoldAccessToken Integer
dur UUID
usr Maybe Text
cid Word64
con = do
  POSIXTime
d <- Integer -> Create POSIXTime
forall (m :: * -> *). MonadIO m => Integer -> m POSIXTime
expiry Integer
dur
  POSIXTime
-> Type
-> Maybe Tag
-> LegalHoldAccess
-> Create (Token LegalHoldAccess)
forall a.
ToByteString a =>
POSIXTime -> Type -> Maybe Tag -> a -> Create (Token a)
newToken POSIXTime
d Type
LA Maybe Tag
forall a. Maybe a
Nothing (UUID -> Maybe Text -> Word64 -> LegalHoldAccess
mkLegalHoldAccess UUID
usr Maybe Text
cid Word64
con)

-- | Create a legal hold access token taking a duration, userId. Similar to 'legalHoldAccessToken', except that the connection identifier is randomly generated.
legalHoldAccessToken1 :: Integer -> UUID -> Maybe Text -> Create (Token LegalHoldAccess)
legalHoldAccessToken1 :: Integer -> UUID -> Maybe Text -> Create (Token LegalHoldAccess)
legalHoldAccessToken1 Integer
dur UUID
usr Maybe Text
cid = do
  Gen RealWorld
g <- ReaderT Env IO (Gen RealWorld) -> Create (Gen RealWorld)
forall a. ReaderT Env IO a -> Create a
Create (ReaderT Env IO (Gen RealWorld) -> Create (Gen RealWorld))
-> ReaderT Env IO (Gen RealWorld) -> Create (Gen RealWorld)
forall a b. (a -> b) -> a -> b
$ (Env -> Gen RealWorld) -> ReaderT Env IO (Gen RealWorld)
forall r (m :: * -> *) a. MonadReader r m => (r -> a) -> m a
asks Env -> Gen RealWorld
Env -> GenIO
randGen
  Word64
d <- IO Word64 -> Create Word64
forall a. IO a -> Create a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO Word64 -> Create Word64) -> IO Word64 -> Create Word64
forall a b. (a -> b) -> a -> b
$ (GenIO -> IO Word64) -> GenIO -> IO Word64
forall a. (GenIO -> IO a) -> GenIO -> IO a
asGenIO (GenIO -> IO Word64
forall a (m :: * -> *).
(Variate a, PrimMonad m) =>
Gen (PrimState m) -> m a
forall (m :: * -> *). PrimMonad m => Gen (PrimState m) -> m Word64
uniform :: GenIO -> IO Word64) Gen RealWorld
GenIO
g
  Integer
-> UUID -> Maybe Text -> Word64 -> Create (Token LegalHoldAccess)
legalHoldAccessToken Integer
dur UUID
usr Maybe Text
cid Word64
d

botToken :: UUID -> UUID -> UUID -> Create (Token Bot)
botToken :: UUID -> UUID -> UUID -> Create (Token Bot)
botToken UUID
pid UUID
bid UUID
cnv = POSIXTime -> Type -> Maybe Tag -> Bot -> Create (Token Bot)
forall a.
ToByteString a =>
POSIXTime -> Type -> Maybe Tag -> a -> Create (Token a)
newToken (-POSIXTime
1) Type
B Maybe Tag
forall a. Maybe a
Nothing (UUID -> UUID -> UUID -> Bot
mkBot UUID
pid UUID
bid UUID
cnv)

providerToken :: Integer -> UUID -> Create (Token Provider)
providerToken :: Integer -> UUID -> Create (Token Provider)
providerToken Integer
dur UUID
pid = do
  POSIXTime
d <- Integer -> Create POSIXTime
forall (m :: * -> *). MonadIO m => Integer -> m POSIXTime
expiry Integer
dur
  POSIXTime
-> Type -> Maybe Tag -> Provider -> Create (Token Provider)
forall a.
ToByteString a =>
POSIXTime -> Type -> Maybe Tag -> a -> Create (Token a)
newToken POSIXTime
d Type
P Maybe Tag
forall a. Maybe a
Nothing (UUID -> Provider
mkProvider UUID
pid)

renewToken :: (ToByteString a) => Integer -> Header -> a -> Create (Token a)
renewToken :: forall a.
ToByteString a =>
Integer -> Header -> a -> Create (Token a)
renewToken Integer
dur Header
hdr a
bdy = do
  POSIXTime
d <- Integer -> Create POSIXTime
forall (m :: * -> *). MonadIO m => Integer -> m POSIXTime
expiry Integer
dur
  POSIXTime -> Type -> Maybe Tag -> a -> Create (Token a)
forall a.
ToByteString a =>
POSIXTime -> Type -> Maybe Tag -> a -> Create (Token a)
newToken POSIXTime
d (Header
hdr Header -> Getting Type Header Type -> Type
forall s a. s -> Getting a s a -> a
^. Getting Type Header Type
Lens' Header Type
typ) (Header
hdr Header -> Getting (Maybe Tag) Header (Maybe Tag) -> Maybe Tag
forall s a. s -> Getting a s a -> a
^. Getting (Maybe Tag) Header (Maybe Tag)
Lens' Header (Maybe Tag)
tag) a
bdy

newToken :: (ToByteString a) => POSIXTime -> Type -> Maybe Tag -> a -> Create (Token a)
newToken :: forall a.
ToByteString a =>
POSIXTime -> Type -> Maybe Tag -> a -> Create (Token a)
newToken POSIXTime
ti Type
ty Maybe Tag
ta a
a = do
  Int
k <- ReaderT Env IO Int -> Create Int
forall a. ReaderT Env IO a -> Create a
Create (ReaderT Env IO Int -> Create Int)
-> ReaderT Env IO Int -> Create Int
forall a b. (a -> b) -> a -> b
$ (Env -> Int) -> ReaderT Env IO Int
forall r (m :: * -> *) a. MonadReader r m => (r -> a) -> m a
asks Env -> Int
keyIdx
  let h :: Header
h = Int -> Int -> Integer -> Type -> Maybe Tag -> Header
mkHeader Int
tokenVersion Int
k (POSIXTime -> Integer
forall b. Integral b => POSIXTime -> b
forall a b. (RealFrac a, Integral b) => a -> b
floor POSIXTime
ti) Type
ty Maybe Tag
ta
  Signature
s <- Header -> a -> Create Signature
forall a. ToByteString a => Header -> a -> Create Signature
signToken Header
h a
a
  Token a -> Create (Token a)
forall a. a -> Create a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Token a -> Create (Token a)) -> Token a -> Create (Token a)
forall a b. (a -> b) -> a -> b
$ Signature -> Header -> a -> Token a
forall a. Signature -> Header -> a -> Token a
mkToken Signature
s Header
h a
a

-----------------------------------------------------------------------------
-- Internal

signToken :: (ToByteString a) => Header -> a -> Create Signature
signToken :: forall a. ToByteString a => Header -> a -> Create Signature
signToken Header
h a
a = ReaderT Env IO Signature -> Create Signature
forall a. ReaderT Env IO a -> Create a
Create (ReaderT Env IO Signature -> Create Signature)
-> ReaderT Env IO Signature -> Create Signature
forall a b. (a -> b) -> a -> b
$ do
  ByteString -> IO Signature
f <- (Vector (ByteString -> IO Signature)
-> Int -> ByteString -> IO Signature
forall a. Vector a -> Int -> a
! (Header
h Header -> Getting Int Header Int -> Int
forall s a. s -> Getting a s a -> a
^. Getting Int Header Int
Lens' Header Int
key Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1)) (Vector (ByteString -> IO Signature) -> ByteString -> IO Signature)
-> ReaderT Env IO (Vector (ByteString -> IO Signature))
-> ReaderT Env IO (ByteString -> IO Signature)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (Env -> Vector (ByteString -> IO Signature))
-> ReaderT Env IO (Vector (ByteString -> IO Signature))
forall r (m :: * -> *) a. MonadReader r m => (r -> a) -> m a
asks Env -> Vector (ByteString -> IO Signature)
zSign
  IO Signature -> ReaderT Env IO Signature
forall a. IO a -> ReaderT Env IO a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO Signature -> ReaderT Env IO Signature)
-> (Builder -> IO Signature) -> Builder -> ReaderT Env IO Signature
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> IO Signature
f (ByteString -> IO Signature)
-> (Builder -> ByteString) -> Builder -> IO Signature
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> ByteString
toStrict (ByteString -> ByteString)
-> (Builder -> ByteString) -> Builder -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Builder -> ByteString
toLazyByteString (Builder -> ReaderT Env IO Signature)
-> Builder -> ReaderT Env IO Signature
forall a b. (a -> b) -> a -> b
$ Header -> a -> Builder
forall a. ToByteString a => Header -> a -> Builder
writeData Header
h a
a

expiry :: (MonadIO m) => Integer -> m POSIXTime
expiry :: forall (m :: * -> *). MonadIO m => Integer -> m POSIXTime
expiry Integer
d = (Integer -> POSIXTime
forall a. Num a => Integer -> a
fromInteger Integer
d +) (POSIXTime -> POSIXTime) -> m POSIXTime -> m POSIXTime
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> IO POSIXTime -> m POSIXTime
forall a. IO a -> m a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO IO POSIXTime
getPOSIXTime