logging
This commit is contained in:
parent
452477fc11
commit
3eee205eaf
10 changed files with 68 additions and 27 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -4,3 +4,5 @@ templates/
|
||||||
website/
|
website/
|
||||||
user-data/
|
user-data/
|
||||||
out/
|
out/
|
||||||
|
notes/
|
||||||
|
fedi.log
|
||||||
|
|
|
@ -42,12 +42,14 @@ data NoteEntry
|
||||||
, name :: Maybe String
|
, name :: Maybe String
|
||||||
, url :: Maybe Url
|
, url :: Maybe Url
|
||||||
}
|
}
|
||||||
|
deriving Show
|
||||||
|
|
||||||
data FollowerEntry
|
data FollowerEntry
|
||||||
= FollowerEntry
|
= FollowerEntry
|
||||||
{ followId :: T.Text
|
{ followId :: T.Text
|
||||||
, actorId :: T.Text
|
, actorId :: T.Text
|
||||||
}
|
}
|
||||||
|
deriving Show
|
||||||
|
|
||||||
data Follower
|
data Follower
|
||||||
= Follower
|
= Follower
|
||||||
|
@ -55,6 +57,7 @@ data Follower
|
||||||
, followId :: T.Text
|
, followId :: T.Text
|
||||||
, actorId :: T.Text
|
, actorId :: T.Text
|
||||||
}
|
}
|
||||||
|
deriving Show
|
||||||
|
|
||||||
-----------------------
|
-----------------------
|
||||||
|
|
||||||
|
|
19
app/Main.hs
19
app/Main.hs
|
@ -16,6 +16,7 @@ import Network.Wai.Middleware.Routed qualified as Wai
|
||||||
import Routes
|
import Routes
|
||||||
import System.Environment (getArgs, lookupEnv)
|
import System.Environment (getArgs, lookupEnv)
|
||||||
import Web.Twain qualified as Twain
|
import Web.Twain qualified as Twain
|
||||||
|
import Control.Logger.Simple qualified as Log
|
||||||
|
|
||||||
data Command
|
data Command
|
||||||
= Serve
|
= Serve
|
||||||
|
@ -63,15 +64,18 @@ insertNoteFromFile file = do
|
||||||
print note
|
print note
|
||||||
|
|
||||||
serve :: IO ()
|
serve :: IO ()
|
||||||
serve = do
|
serve = Log.withGlobalLogging (Log.LogConfig (Just "fedi.log") True) do
|
||||||
|
logLevel <- maybe Log.LogDebug read <$> lookupEnv "FEDI_LOG_LEVEL"
|
||||||
|
Log.setLogLevel logLevel
|
||||||
|
|
||||||
auth <- fmap (T.splitOn "," . T.pack) <$> lookupEnv "FEDI_AUTH"
|
auth <- fmap (T.splitOn "," . T.pack) <$> lookupEnv "FEDI_AUTH"
|
||||||
authMiddleware <-
|
authMiddleware <-
|
||||||
case auth of
|
case auth of
|
||||||
Nothing -> do
|
Nothing -> do
|
||||||
putStrLn "Starting server with authentication disabled."
|
Log.logInfo "Starting server with authentication disabled."
|
||||||
pure id
|
pure id
|
||||||
Just [user, pass] -> do
|
Just [user, pass] -> do
|
||||||
putStrLn "Starting server with authentication enabled,"
|
Log.logInfo "Starting server with authentication enabled,"
|
||||||
let
|
let
|
||||||
username = secureMemFromByteString $ T.encodeUtf8 user
|
username = secureMemFromByteString $ T.encodeUtf8 user
|
||||||
password = secureMemFromByteString $ T.encodeUtf8 pass
|
password = secureMemFromByteString $ T.encodeUtf8 pass
|
||||||
|
@ -87,7 +91,7 @@ serve = do
|
||||||
|
|
||||||
fediPort <- maybe 3001 read <$> lookupEnv "FEDI_PORT"
|
fediPort <- maybe 3001 read <$> lookupEnv "FEDI_PORT"
|
||||||
conn <- maybe "/tmp/fediserve_sqlite_db.sqlite" fromString <$> lookupEnv "FEDI_CONN_STRING"
|
conn <- maybe "/tmp/fediserve_sqlite_db.sqlite" fromString <$> lookupEnv "FEDI_CONN_STRING"
|
||||||
putStrLn $ "and with connection string " <> show (Sqlite.unConnectionString conn) <> "."
|
Log.logInfo $ "and with connection string " <> Sqlite.unConnectionString conn <> "."
|
||||||
|
|
||||||
runServer fediPort authMiddleware =<< mkFediApp conn
|
runServer fediPort authMiddleware =<< mkFediApp conn
|
||||||
|
|
||||||
|
@ -101,15 +105,16 @@ usageError =
|
||||||
, " - FEDI_DETAILS=<FILE>"
|
, " - FEDI_DETAILS=<FILE>"
|
||||||
, " - FEDI_CONN_STRING=<SQLITE_CONN_STR>"
|
, " - FEDI_CONN_STRING=<SQLITE_CONN_STR>"
|
||||||
, " - FEDI_AUTH=<user>,<password>"
|
, " - FEDI_AUTH=<user>,<password>"
|
||||||
|
, " - FEDI_LOG=[ LogTrace | LogDebug | LogInfo | LogNote | LogWarn | LogError ]"
|
||||||
]
|
]
|
||||||
|
|
||||||
-- | Run server at at specific port.
|
-- | Run server at at specific port.
|
||||||
runServer :: Port -> Twain.Middleware -> Twain.Application -> IO ()
|
runServer :: Port -> Twain.Middleware -> Twain.Application -> IO ()
|
||||||
runServer port authMiddleware app = do
|
runServer port authMiddleware app = do
|
||||||
putStrLn $
|
Log.logInfo $
|
||||||
unwords
|
T.unwords
|
||||||
[ "Running fedi at"
|
[ "Running fedi at"
|
||||||
, "http://localhost:" <> show port
|
, "http://localhost:" <> T.pack (show port)
|
||||||
, "(ctrl-c to quit)"
|
, "(ctrl-c to quit)"
|
||||||
]
|
]
|
||||||
auth <- Wai.routedMiddleware matchAdmin <$> pure authMiddleware
|
auth <- Wai.routedMiddleware matchAdmin <$> pure authMiddleware
|
||||||
|
|
|
@ -11,6 +11,7 @@ import System.IO.Unsafe (unsafePerformIO)
|
||||||
import Web.Twain qualified as Twain
|
import Web.Twain qualified as Twain
|
||||||
import Data.Text qualified as T
|
import Data.Text qualified as T
|
||||||
import Control.Concurrent.Async qualified as Async
|
import Control.Concurrent.Async qualified as Async
|
||||||
|
import Control.Logger.Simple qualified as Log
|
||||||
|
|
||||||
routes :: DB -> FilePath -> [Twain.Middleware]
|
routes :: DB -> FilePath -> [Twain.Middleware]
|
||||||
routes db detailsFile =
|
routes db detailsFile =
|
||||||
|
@ -48,6 +49,7 @@ routes db detailsFile =
|
||||||
|
|
||||||
, -- Match inbox
|
, -- Match inbox
|
||||||
Twain.post (Fedi.matchInbox $ unsafePerformIO $ fetchUserDetails detailsFile) do
|
Twain.post (Fedi.matchInbox $ unsafePerformIO $ fetchUserDetails detailsFile) do
|
||||||
|
Log.logTrace "Inbox"
|
||||||
Fedi.handleInbox (handleInbox db detailsFile)
|
Fedi.handleInbox (handleInbox db detailsFile)
|
||||||
|
|
||||||
, -- Match Create object
|
, -- Match Create object
|
||||||
|
@ -128,6 +130,7 @@ noteToCreate note = Fedi.makeCreateNote note
|
||||||
handleInbox :: DB -> FilePath -> Fedi.AnyActivity -> Twain.ResponderM Twain.Response
|
handleInbox :: DB -> FilePath -> Fedi.AnyActivity -> Twain.ResponderM Twain.Response
|
||||||
handleInbox db detailsFile activity = do
|
handleInbox db detailsFile activity = do
|
||||||
details <- liftIO $ fetchUserDetails detailsFile
|
details <- liftIO $ fetchUserDetails detailsFile
|
||||||
|
Log.logDebug (Fedi.pShow activity)
|
||||||
case activity of
|
case activity of
|
||||||
Fedi.ActivityFollow follow -> do
|
Fedi.ActivityFollow follow -> do
|
||||||
let
|
let
|
||||||
|
@ -153,11 +156,12 @@ handleInbox db detailsFile activity = do
|
||||||
follow
|
follow
|
||||||
(Fedi.actorUrl details <> "/accepts/follows/" <> show insertId)
|
(Fedi.actorUrl details <> "/accepts/follows/" <> show insertId)
|
||||||
)
|
)
|
||||||
print result
|
Log.logDebug (Fedi.pShow result)
|
||||||
pure $ Fedi.jsonLD "{}"
|
pure $ Twain.text ""
|
||||||
)
|
)
|
||||||
liftIO do
|
liftIO do
|
||||||
insertFollower db followerEntry callback
|
insertFollower db followerEntry callback
|
||||||
|
<* Log.logInfo ("New follower: " <> Fedi.pShow followerEntry)
|
||||||
else Twain.next
|
else Twain.next
|
||||||
Nothing ->
|
Nothing ->
|
||||||
Twain.next
|
Twain.next
|
||||||
|
@ -182,19 +186,21 @@ handleInbox db detailsFile activity = do
|
||||||
{ actorId = fromString actor.unwrap
|
{ actorId = fromString actor.unwrap
|
||||||
, followId = fromString id''.unwrap
|
, followId = fromString id''.unwrap
|
||||||
}
|
}
|
||||||
print ("deleted follower: " <> show deletedId)
|
Log.logInfo ("deleted follower: " <> Fedi.pShow deletedId)
|
||||||
pure $ Fedi.jsonLD "{}"
|
pure $ Twain.text ""
|
||||||
else Twain.next
|
else Twain.next
|
||||||
Nothing ->
|
Nothing ->
|
||||||
Twain.next
|
Twain.next
|
||||||
_ -> do
|
_ -> do
|
||||||
liftIO (print activity)
|
Log.logError $ "Unsupported activity: " <> Fedi.pShow activity
|
||||||
Twain.next
|
Twain.next
|
||||||
|
|
||||||
sendFollowers :: Fedi.UserDetails -> DB -> Fedi.AnyActivity -> IO ()
|
sendFollowers :: Fedi.UserDetails -> DB -> Fedi.AnyActivity -> IO ()
|
||||||
sendFollowers details db message = do
|
sendFollowers details db message = do
|
||||||
|
Log.logDebug $ "Sending to followers: " <> Fedi.pShow message
|
||||||
followers <- db.getFollowers
|
followers <- db.getFollowers
|
||||||
Fedi.for_ followers \follower -> do
|
Fedi.for_ followers \follower -> do
|
||||||
Async.async $ do
|
Async.async $ do
|
||||||
|
Log.logDebug $ "Sending to follower: " <> Fedi.pShow follower.actorId
|
||||||
bs <- Fedi.sendPost details (T.unpack follower.actorId <> "/inbox") message
|
bs <- Fedi.sendPost details (T.unpack follower.actorId <> "/inbox") message
|
||||||
print (follower.actorId, bs)
|
Log.logDebug $ "Sent to follower: " <> Fedi.pShow (follower.actorId, bs)
|
||||||
|
|
|
@ -64,6 +64,8 @@ library
|
||||||
, raw-strings-qq
|
, raw-strings-qq
|
||||||
, case-insensitive
|
, case-insensitive
|
||||||
, http-types
|
, http-types
|
||||||
|
, simple-logger
|
||||||
|
, pretty-simple
|
||||||
|
|
||||||
hs-source-dirs: src
|
hs-source-dirs: src
|
||||||
default-language: GHC2021
|
default-language: GHC2021
|
||||||
|
@ -102,6 +104,8 @@ executable fedi
|
||||||
, raw-strings-qq
|
, raw-strings-qq
|
||||||
, securemem
|
, securemem
|
||||||
, lucid2
|
, lucid2
|
||||||
|
, simple-logger
|
||||||
|
, pretty-simple
|
||||||
|
|
||||||
hs-source-dirs: app
|
hs-source-dirs: app
|
||||||
default-language: GHC2021
|
default-language: GHC2021
|
||||||
|
|
|
@ -12,14 +12,16 @@ import Fedi.Helpers
|
||||||
import Data.ByteString.Base64 qualified as Base64
|
import Data.ByteString.Base64 qualified as Base64
|
||||||
import Data.Base64.Types qualified as Base64
|
import Data.Base64.Types qualified as Base64
|
||||||
import Data.Text qualified as T
|
import Data.Text qualified as T
|
||||||
|
import Control.Logger.Simple qualified as Log
|
||||||
|
import Control.Monad.IO.Class
|
||||||
|
|
||||||
-- import Debug.Trace
|
verifyPub :: MonadIO m => MonadThrow m => ByteString -> ByteString -> ByteString -> m Bool
|
||||||
|
|
||||||
verifyPub :: MonadThrow m => ByteString -> ByteString -> ByteString -> m Bool
|
|
||||||
verifyPub pubkeypem sig message = do
|
verifyPub pubkeypem sig message = do
|
||||||
-- traceShowM ("pubkeypem", pubkeypem)
|
Log.logDebug $ "Verifying signature: " <> pShow
|
||||||
-- traceShowM ("sig", sig)
|
[ ("pubkeypem", pubkeypem)
|
||||||
-- traceShowM ("mssage", message)
|
, ("sig", sig)
|
||||||
|
, ("message", message)
|
||||||
|
]
|
||||||
|
|
||||||
pubkey <-
|
pubkey <-
|
||||||
case Crypto.readPubKeyFileFromMemory pubkeypem of
|
case Crypto.readPubKeyFileFromMemory pubkeypem of
|
||||||
|
|
|
@ -17,6 +17,8 @@ import Control.Monad as Export
|
||||||
import Data.Functor as Export
|
import Data.Functor as Export
|
||||||
import Data.Function as Export
|
import Data.Function as Export
|
||||||
import Control.Monad.Catch as Export (throwM, Exception, MonadThrow)
|
import Control.Monad.Catch as Export (throwM, Exception, MonadThrow)
|
||||||
|
import Text.Pretty.Simple qualified as PS
|
||||||
|
import Data.Text.Lazy qualified as TL
|
||||||
|
|
||||||
data Error
|
data Error
|
||||||
= Error String
|
= Error String
|
||||||
|
@ -24,3 +26,6 @@ data Error
|
||||||
|
|
||||||
throw :: MonadThrow m => String -> m a
|
throw :: MonadThrow m => String -> m a
|
||||||
throw = throwM . Error
|
throw = throwM . Error
|
||||||
|
|
||||||
|
pShow :: Show a => a -> Text
|
||||||
|
pShow = TL.toStrict . PS.pShow
|
||||||
|
|
|
@ -11,6 +11,7 @@ import Network.HTTP.Req qualified as Req
|
||||||
import Data.ByteString.Lazy qualified as BSL
|
import Data.ByteString.Lazy qualified as BSL
|
||||||
import Text.URI qualified as URI
|
import Text.URI qualified as URI
|
||||||
import Data.Text qualified as T
|
import Data.Text qualified as T
|
||||||
|
import Control.Logger.Simple qualified as Log
|
||||||
|
|
||||||
sendPost
|
sendPost
|
||||||
:: A.ToJSON input
|
:: A.ToJSON input
|
||||||
|
@ -22,10 +23,12 @@ sendPost details url payload = do
|
||||||
uri <- URI.mkURI $ fromString url
|
uri <- URI.mkURI $ fromString url
|
||||||
let encoded = BSL.toStrict $ A.encode payload
|
let encoded = BSL.toStrict $ A.encode payload
|
||||||
httpSignature <- makeHttpSignature details uri encoded
|
httpSignature <- makeHttpSignature details uri encoded
|
||||||
|
Log.logDebug $ "http signature: " <> pShow httpSignature
|
||||||
|
Log.logDebug $ "http signature headers: " <> pShow (makeSigHeaders httpSignature)
|
||||||
(url', scheme) <- maybe (throw "couldn't parse uri") pure (Req.useHttpsURI uri)
|
(url', scheme) <- maybe (throw "couldn't parse uri") pure (Req.useHttpsURI uri)
|
||||||
Req.runReq Req.defaultHttpConfig do
|
Req.runReq Req.defaultHttpConfig do
|
||||||
r <-
|
response <-
|
||||||
Req.req
|
Req.reqCb
|
||||||
Req.POST
|
Req.POST
|
||||||
url'
|
url'
|
||||||
(Req.ReqBodyBs encoded)
|
(Req.ReqBodyBs encoded)
|
||||||
|
@ -33,7 +36,12 @@ sendPost details url payload = do
|
||||||
( scheme
|
( scheme
|
||||||
<> sigHeaders httpSignature
|
<> sigHeaders httpSignature
|
||||||
)
|
)
|
||||||
pure $ Req.responseBody r
|
(\request -> do
|
||||||
|
Log.logDebug $ "Sending POST request: " <> pShow request
|
||||||
|
pure request
|
||||||
|
)
|
||||||
|
Log.logInfo $ "Response: " <> pShow response
|
||||||
|
pure $ Req.responseBody response
|
||||||
|
|
||||||
makeHttpSignature :: UserDetails -> URI.URI -> ByteString -> IO HttpSignature
|
makeHttpSignature :: UserDetails -> URI.URI -> ByteString -> IO HttpSignature
|
||||||
makeHttpSignature details uri encoded = do
|
makeHttpSignature details uri encoded = do
|
||||||
|
@ -71,7 +79,7 @@ sendGet url = do
|
||||||
|
|
||||||
Req.runReq Req.defaultHttpConfig do
|
Req.runReq Req.defaultHttpConfig do
|
||||||
r <-
|
r <-
|
||||||
Req.req
|
Req.reqCb
|
||||||
Req.GET
|
Req.GET
|
||||||
url'
|
url'
|
||||||
Req.NoReqBody
|
Req.NoReqBody
|
||||||
|
@ -79,4 +87,8 @@ sendGet url = do
|
||||||
( scheme
|
( scheme
|
||||||
<> Req.header "ContentType" "application/activity+json"
|
<> Req.header "ContentType" "application/activity+json"
|
||||||
)
|
)
|
||||||
|
(\request -> do
|
||||||
|
Log.logDebug $ "Sending GET request: " <> pShow request
|
||||||
|
pure request
|
||||||
|
)
|
||||||
pure $ Req.responseBody r
|
pure $ Req.responseBody r
|
||||||
|
|
|
@ -2,12 +2,13 @@ module Fedi.Routes.Inbox where
|
||||||
|
|
||||||
import Prelude hiding (error)
|
import Prelude hiding (error)
|
||||||
import Fedi.Types
|
import Fedi.Types
|
||||||
|
import Fedi.Helpers
|
||||||
import Fedi.UserDetails
|
import Fedi.UserDetails
|
||||||
import Web.Twain qualified as Twain
|
import Web.Twain qualified as Twain
|
||||||
import Web.Twain.Types qualified as Twain
|
import Web.Twain.Types qualified as Twain
|
||||||
import Control.Monad.IO.Class (liftIO)
|
|
||||||
import Control.Monad.Catch (catch, displayException, SomeException)
|
import Control.Monad.Catch (catch, displayException, SomeException)
|
||||||
import Fedi.Signature.Check
|
import Fedi.Signature.Check
|
||||||
|
import Control.Logger.Simple qualified as Log
|
||||||
|
|
||||||
-- * Inbox
|
-- * Inbox
|
||||||
|
|
||||||
|
@ -23,7 +24,8 @@ handleInbox handle = do
|
||||||
response <- handle activity
|
response <- handle activity
|
||||||
Twain.send response
|
Twain.send response
|
||||||
handler `catch` \(e :: SomeException) -> do
|
handler `catch` \(e :: SomeException) -> do
|
||||||
liftIO $ putStrLn (displayException e)
|
Log.logError (pShow $ displayException e)
|
||||||
Twain.send $
|
Twain.send $
|
||||||
|
-- not necessarily 500, but we'll do this for now.
|
||||||
Twain.status Twain.status500 $
|
Twain.status Twain.status500 $
|
||||||
Twain.text "Internal Server Error 500"
|
Twain.text "Internal Server Error 500"
|
||||||
|
|
|
@ -17,7 +17,6 @@ import Web.Twain qualified as Twain
|
||||||
import Data.Text qualified as T
|
import Data.Text qualified as T
|
||||||
import Network.Wai qualified as Wai
|
import Network.Wai qualified as Wai
|
||||||
import Network.HTTP.Types.URI qualified as HTTP
|
import Network.HTTP.Types.URI qualified as HTTP
|
||||||
import Control.Monad.IO.Class (liftIO)
|
|
||||||
import Text.ParserCombinators.ReadP qualified as P
|
import Text.ParserCombinators.ReadP qualified as P
|
||||||
import Data.Text.Encoding qualified as T
|
import Data.Text.Encoding qualified as T
|
||||||
import Data.ByteString qualified as BS
|
import Data.ByteString qualified as BS
|
||||||
|
@ -25,6 +24,7 @@ import Data.ByteString.Lazy qualified as BSL
|
||||||
import Fedi.Crypto
|
import Fedi.Crypto
|
||||||
import Fedi.Signature.Types
|
import Fedi.Signature.Types
|
||||||
import Data.CaseInsensitive qualified as CI
|
import Data.CaseInsensitive qualified as CI
|
||||||
|
import Control.Monad.IO.Class
|
||||||
|
|
||||||
-- * Check
|
-- * Check
|
||||||
|
|
||||||
|
@ -83,7 +83,7 @@ makeSignatureString request (map (T.encodeUtf8 . T.toLower) -> headers) = do
|
||||||
BS.intercalate "\n" <$> traverse mylookup headers
|
BS.intercalate "\n" <$> traverse mylookup headers
|
||||||
|
|
||||||
checkSignature
|
checkSignature
|
||||||
:: MonadThrow m
|
:: MonadIO m => MonadThrow m
|
||||||
=> Url -> ByteString -> SignatureHeader -> ByteString -> ByteString -> ByteString -> m ()
|
=> Url -> ByteString -> SignatureHeader -> ByteString -> ByteString -> ByteString -> m ()
|
||||||
checkSignature personPkid personPublicKey sigheader signatureString digest body = do
|
checkSignature personPkid personPublicKey sigheader signatureString digest body = do
|
||||||
-- check
|
-- check
|
||||||
|
|
Loading…
Add table
Reference in a new issue