feat(users/Profpatsch/whatcd-resolver): read redacted key from env

Change-Id: I5667710423aeeacfbb8dddf5b0b8750dc8f878aa
Reviewed-on: https://cl.tvl.fyi/c/depot/+/12055
Tested-by: BuildkiteCI
Reviewed-by: Profpatsch <mail@profpatsch.de>
This commit is contained in:
Profpatsch 2024-07-29 11:47:20 +02:00
parent 1f65a7b0d0
commit a86dca8c78
3 changed files with 44 additions and 17 deletions

View file

@ -12,6 +12,8 @@ import Data.Pool (Pool)
import Data.Text qualified as Text import Data.Text qualified as Text
import Database.PostgreSQL.Simple qualified as Postgres import Database.PostgreSQL.Simple qualified as Postgres
import GHC.Stack qualified import GHC.Stack qualified
import Json.Enc
import Json.Enc qualified as Enc
import Label import Label
import OpenTelemetry.Trace qualified as Otel hiding (getTracer, inSpan, inSpan') import OpenTelemetry.Trace qualified as Otel hiding (getTracer, inSpan, inSpan')
import OpenTelemetry.Trace.Core qualified as Otel hiding (inSpan, inSpan') import OpenTelemetry.Trace.Core qualified as Otel hiding (inSpan, inSpan')
@ -27,7 +29,8 @@ data Context = Context
tracer :: Otel.Tracer, tracer :: Otel.Tracer,
pgFormat :: PgFormatPool, pgFormat :: PgFormatPool,
pgConnPool :: Pool Postgres.Connection, pgConnPool :: Pool Postgres.Connection,
transmissionSessionId :: IORef (Maybe ByteString) transmissionSessionId :: IORef (Maybe ByteString),
redactedApiKey :: ByteString
} }
newtype AppT m a = AppT {unAppT :: ReaderT Context m a} newtype AppT m a = AppT {unAppT :: ReaderT Context m a}
@ -67,6 +70,15 @@ addAttribute span key a = Otel.addAttribute span ("_." <> key) a
addAttributes :: (MonadIO m) => Otel.Span -> HashMap Text Otel.Attribute -> m () addAttributes :: (MonadIO m) => Otel.Span -> HashMap Text Otel.Attribute -> m ()
addAttributes span attrs = Otel.addAttributes span $ attrs & HashMap.mapKeys ("_." <>) addAttributes span attrs = Otel.addAttributes span $ attrs & HashMap.mapKeys ("_." <>)
-- | Create an otel attribute from a json encoder
jsonAttribute :: Enc -> Otel.Attribute
jsonAttribute e = e & Enc.encToTextPretty & Otel.toAttribute
orThrowAppErrorNewSpan :: (MonadThrow m, MonadOtel m) => Text -> Either ErrorTree a -> m a
orThrowAppErrorNewSpan msg = \case
Left err -> appThrowTreeNewSpan msg err
Right a -> pure a
appThrowTreeNewSpan :: (MonadThrow m, MonadOtel m) => Text -> ErrorTree -> m a appThrowTreeNewSpan :: (MonadThrow m, MonadOtel m) => Text -> ErrorTree -> m a
appThrowTreeNewSpan spanName exc = inSpan' spanName $ \span -> do appThrowTreeNewSpan spanName exc = inSpan' spanName $ \span -> do
let msg = prettyErrorTree exc let msg = prettyErrorTree exc
@ -127,7 +139,7 @@ recordException span dat = liftIO $ do
HashMap.fromList HashMap.fromList
[ ("exception.type", Otel.toAttribute @Text dat.type_), [ ("exception.type", Otel.toAttribute @Text dat.type_),
("exception.message", Otel.toAttribute @Text dat.message), ("exception.message", Otel.toAttribute @Text dat.message),
("exception.stacktrace", Otel.toAttribute @Text $ Text.unlines $ map stringToText callStack) ("exception.stacktrace", Otel.toAttribute @Text $ Text.unlines $ Prelude.map stringToText callStack)
], ],
.. ..
} }

View file

@ -27,11 +27,16 @@ import Optional
import Postgres.Decoder qualified as Dec import Postgres.Decoder qualified as Dec
import Postgres.MonadPostgres import Postgres.MonadPostgres
import Pretty import Pretty
import RunCommand (runCommandExpect0)
import Prelude hiding (span) import Prelude hiding (span)
class MonadRedacted m where
getRedactedApiKey :: m ByteString
instance (MonadIO m) => MonadRedacted (AppT m) where
getRedactedApiKey = AppT (asks (.redactedApiKey))
redactedSearch :: redactedSearch ::
(MonadLogger m, MonadThrow m, MonadOtel m) => (MonadThrow m, MonadOtel m, MonadRedacted m) =>
[(ByteString, ByteString)] -> [(ByteString, ByteString)] ->
Json.Parse ErrorTree a -> Json.Parse ErrorTree a ->
m a m a
@ -48,7 +53,8 @@ redactedGetTorrentFile ::
( MonadLogger m, ( MonadLogger m,
MonadThrow m, MonadThrow m,
HasField "torrentId" dat Int, HasField "torrentId" dat Int,
MonadOtel m MonadOtel m,
MonadRedacted m
) => ) =>
dat -> dat ->
m ByteString m ByteString
@ -71,7 +77,7 @@ redactedGetTorrentFile dat = inSpan' "Redacted Get Torrent File" $ \span -> do
mkRedactedTorrentLink :: Arg "torrentGroupId" Int -> Text mkRedactedTorrentLink :: Arg "torrentGroupId" Int -> Text
mkRedactedTorrentLink torrentId = [fmt|https://redacted.ch/torrents.php?id={torrentId.unArg}|] mkRedactedTorrentLink torrentId = [fmt|https://redacted.ch/torrents.php?id={torrentId.unArg}|]
exampleSearch :: (MonadThrow m, MonadLogger m, MonadPostgres m, MonadOtel m) => m (Transaction m ()) exampleSearch :: (MonadThrow m, MonadLogger m, MonadPostgres m, MonadOtel m, MonadRedacted m) => m (Transaction m ())
exampleSearch = do exampleSearch = do
t1 <- t1 <-
redactedSearchAndInsert redactedSearchAndInsert
@ -108,7 +114,8 @@ redactedSearchAndInsert ::
( MonadLogger m, ( MonadLogger m,
MonadPostgres m, MonadPostgres m,
MonadThrow m, MonadThrow m,
MonadOtel m MonadOtel m,
MonadRedacted m
) => ) =>
[(ByteString, ByteString)] -> [(ByteString, ByteString)] ->
m (Transaction m ()) m (Transaction m ())
@ -289,12 +296,13 @@ redactedGetTorrentFileAndInsert ::
MonadPostgres m, MonadPostgres m,
MonadThrow m, MonadThrow m,
MonadLogger m, MonadLogger m,
MonadOtel m MonadOtel m,
MonadRedacted m
) => ) =>
r -> r ->
Transaction m (Label "torrentFile" ByteString) Transaction m (Label "torrentFile" ByteString)
redactedGetTorrentFileAndInsert dat = inSpan' "Redacted Get Torrent File and Insert" $ \span -> do redactedGetTorrentFileAndInsert dat = inSpan' "Redacted Get Torrent File and Insert" $ \span -> do
bytes <- redactedGetTorrentFile dat bytes <- lift $ redactedGetTorrentFile dat
execute execute
[sql| [sql|
UPDATE redacted.torrents_json UPDATE redacted.torrents_json
@ -468,15 +476,14 @@ getBestTorrents opts = do
-- | Do a request to the redacted API. If you know what that is, you know how to find the API docs. -- | Do a request to the redacted API. If you know what that is, you know how to find the API docs.
mkRedactedApiRequest :: mkRedactedApiRequest ::
( MonadThrow m, ( MonadThrow m,
MonadIO m,
MonadLogger m,
HasField "action" p ByteString, HasField "action" p ByteString,
HasField "actionArgs" p [(ByteString, Maybe ByteString)] HasField "actionArgs" p [(ByteString, Maybe ByteString)],
MonadRedacted m
) => ) =>
p -> p ->
m Http.Request m Http.Request
mkRedactedApiRequest dat = do mkRedactedApiRequest dat = do
authKey <- runCommandExpect0 "pass" ["internet/redacted/api-keys/whatcd-resolver"] authKey <- getRedactedApiKey
pure $ pure $
[fmt|https://redacted.ch/ajax.php|] [fmt|https://redacted.ch/ajax.php|]
& Http.setRequestMethod "GET" & Http.setRequestMethod "GET"
@ -558,10 +565,10 @@ httpJson opts parser req = inSpan' "HTTP Request (JSON)" $ \span -> do
redactedApiRequestJson :: redactedApiRequestJson ::
( MonadThrow m, ( MonadThrow m,
MonadLogger m,
HasField "action" p ByteString, HasField "action" p ByteString,
HasField "actionArgs" p [(ByteString, Maybe ByteString)], HasField "actionArgs" p [(ByteString, Maybe ByteString)],
MonadOtel m MonadOtel m,
MonadRedacted m
) => ) =>
p -> p ->
Json.Parse ErrorTree a -> Json.Parse ErrorTree a ->

View file

@ -11,7 +11,7 @@ import Control.Monad.Reader
import Data.Aeson qualified as Json import Data.Aeson qualified as Json
import Data.Aeson.BetterErrors qualified as Json import Data.Aeson.BetterErrors qualified as Json
import Data.Aeson.KeyMap qualified as KeyMap import Data.Aeson.KeyMap qualified as KeyMap
import Data.Error.Tree (prettyErrorTree) import Data.Error.Tree
import Data.HashMap.Strict qualified as HashMap import Data.HashMap.Strict qualified as HashMap
import Data.List qualified as List import Data.List qualified as List
import Data.Map.Strict qualified as Map import Data.Map.Strict qualified as Map
@ -52,6 +52,7 @@ import Postgres.Decoder qualified as Dec
import Postgres.MonadPostgres import Postgres.MonadPostgres
import Pretty import Pretty
import Redacted import Redacted
import RunCommand (runCommandExpect0)
import System.Directory qualified as Dir import System.Directory qualified as Dir
import System.Directory qualified as Xdg import System.Directory qualified as Xdg
import System.Environment qualified as Env import System.Environment qualified as Env
@ -469,7 +470,8 @@ snipsRedactedSearch ::
HasField "searchstr" r ByteString, HasField "searchstr" r ByteString,
MonadThrow m, MonadThrow m,
MonadTransmission m, MonadTransmission m,
MonadOtel m MonadOtel m,
MonadRedacted m
) => ) =>
r -> r ->
m Html m Html
@ -758,6 +760,12 @@ runAppWith appT = withTracer $ \tracer -> withDb $ \db -> do
{- unusedResourceOpenTime -} 10 {- unusedResourceOpenTime -} 10
{- max resources across all stripes -} 20 {- max resources across all stripes -} 20
transmissionSessionId <- newIORef Nothing transmissionSessionId <- newIORef Nothing
redactedApiKey <-
Env.lookupEnv "WHATCD_RESOLVER_REDACTED_API_KEY" >>= \case
Just k -> pure (k & stringToBytesUtf8)
Nothing -> runStderrLoggingT $ do
logInfo "WHATCD_RESOLVER_REDACTED_API_KEY was not set, trying pass"
runCommandExpect0 "pass" ["internet/redacted/api-keys/whatcd-resolver"]
let newAppT = do let newAppT = do
logInfo [fmt|Running with config: {showPretty config}|] logInfo [fmt|Running with config: {showPretty config}|]
logInfo [fmt|Connected to database at {db & TmpPg.toDataDirectory} on socket {db & TmpPg.toConnectionString}|] logInfo [fmt|Connected to database at {db & TmpPg.toDataDirectory} on socket {db & TmpPg.toConnectionString}|]