diff --git a/changelog.d/5-internal/WPB-7222 b/changelog.d/5-internal/WPB-7222 new file mode 100644 index 00000000000..a434ed6bf87 --- /dev/null +++ b/changelog.d/5-internal/WPB-7222 @@ -0,0 +1 @@ +drop cs in all production code and from Imports diff --git a/libs/bilge/src/Bilge/Request.hs b/libs/bilge/src/Bilge/Request.hs index 30c15eee8e0..1acd96aa03e 100644 --- a/libs/bilge/src/Bilge/Request.hs +++ b/libs/bilge/src/Bilge/Request.hs @@ -82,7 +82,7 @@ import Data.ByteString.Lazy qualified as Lazy import Data.ByteString.Lazy.Char8 qualified as LC import Data.CaseInsensitive (original) import Data.Id (RequestId (..)) -import Imports hiding (cs, intercalate) +import Imports hiding (intercalate) import Network.HTTP.Client (Cookie, GivesPopper, Request, RequestBody (..)) import Network.HTTP.Client qualified as Rq import Network.HTTP.Client.Internal (CookieJar (..), brReadSome, throwHttp) diff --git a/libs/extended/default.nix b/libs/extended/default.nix index ad03254ed71..66687c40075 100644 --- a/libs/extended/default.nix +++ b/libs/extended/default.nix @@ -29,6 +29,7 @@ , servant-client-core , servant-openapi3 , servant-server +, string-conversions , temporary , text , time @@ -69,7 +70,14 @@ mkDerivation { unliftio wai ]; - testHaskellDepends = [ aeson base hspec imports temporary ]; + testHaskellDepends = [ + aeson + base + hspec + imports + string-conversions + temporary + ]; testToolDepends = [ hspec-discover ]; description = "Extended versions of common modules"; license = lib.licenses.agpl3Only; diff --git a/libs/extended/extended.cabal b/libs/extended/extended.cabal index 2bfb4d92022..087fb75843a 100644 --- a/libs/extended/extended.cabal +++ b/libs/extended/extended.cabal @@ -172,6 +172,7 @@ test-suite extended-tests , extended , hspec , imports + , string-conversions , temporary default-language: GHC2021 diff --git a/libs/extended/src/Servant/API/Extended.hs b/libs/extended/src/Servant/API/Extended.hs index c1e87f38beb..a531f141bd7 100644 --- a/libs/extended/src/Servant/API/Extended.hs +++ b/libs/extended/src/Servant/API/Extended.hs @@ -19,6 +19,7 @@ -- errors instead of plaintext. module Servant.API.Extended where +import Data.ByteString import Data.ByteString.Lazy qualified as BL import Data.EitherR (fmapL) import Data.Kind @@ -92,7 +93,7 @@ instance fromMaybe "application/octet-stream" $ lookup hContentType $ requestHeaders request - case canHandleCTypeH (Proxy :: Proxy list) (cs contentTypeH) :: Maybe (BL.ByteString -> Either String a) of + case canHandleCTypeH (Proxy :: Proxy list) (fromStrict contentTypeH) :: Maybe (BL.ByteString -> Either String a) of Nothing -> delayedFail err415 Just f -> pure f -- Body check, we get a body parsing functions as the first argument. diff --git a/libs/extended/src/System/Logger/Extended.hs b/libs/extended/src/System/Logger/Extended.hs index e360da4e852..2b45c3f746c 100644 --- a/libs/extended/src/System/Logger/Extended.hs +++ b/libs/extended/src/System/Logger/Extended.hs @@ -37,9 +37,12 @@ import Control.Monad.Catch import Data.Aeson as Aeson import Data.Aeson.Encoding (list, pair, text) import Data.Aeson.Key qualified as Key +import Data.ByteString (toStrict) import Data.ByteString.Builder qualified as B import Data.ByteString.Lazy.Char8 qualified as L import Data.Map.Lazy qualified as Map +import Data.Text.Encoding +import Data.Text.Encoding.Error import GHC.Generics import Imports import System.Logger as Log @@ -65,7 +68,14 @@ elementToEncoding :: Element' -> Encoding elementToEncoding (Element' fields msgs) = pairs $ fields <> msgsToSeries msgs where msgsToSeries :: [Builder] -> Series - msgsToSeries = pair "msgs" . list (text . cs . eval) + msgsToSeries = + pair "msgs" + . list + ( text + . decodeUtf8With lenientDecode + . toStrict + . eval + ) collect :: [Element] -> Element' collect = foldr go (Element' mempty []) @@ -74,7 +84,14 @@ collect = foldr go (Element' mempty []) go (Bytes b) (Element' f m) = Element' f (b : m) go (Field k v) (Element' f m) = - Element' (f <> pair (Key.fromText . cs . eval $ k) (text . cs . eval $ v)) m + Element' + ( f + <> pair + (Key.fromText . dec . toStrict . eval $ k) + (text . dec . toStrict . eval $ v) + ) + m + dec = decodeUtf8With lenientDecode jsonRenderer :: Renderer jsonRenderer _sep _dateFormat _logLevel = fromEncoding . elementToEncoding . collect @@ -105,7 +122,7 @@ structuredJSONRenderer _sep _dateFmt _lvlThreshold logElems = renderTextList xs = toJSON xs builderToText :: Builder -> Text - builderToText = cs . eval + builderToText = decodeUtf8With lenientDecode . toStrict . eval -- We need to do this to work around https://gitlab.com/twittner/tinylog/-/issues/5 parseLevel :: Text -> Maybe Level diff --git a/libs/extended/test/Test/System/Logger/ExtendedSpec.hs b/libs/extended/test/Test/System/Logger/ExtendedSpec.hs index 7516a6f7014..753ba59ada7 100644 --- a/libs/extended/test/Test/System/Logger/ExtendedSpec.hs +++ b/libs/extended/test/Test/System/Logger/ExtendedSpec.hs @@ -19,6 +19,7 @@ module Test.System.Logger.ExtendedSpec where import Data.Aeson ((.=)) import Data.Aeson qualified as Aeson +import Data.String.Conversions import Imports import System.IO.Temp import System.Logger.Extended hiding ((.=)) diff --git a/libs/galley-types/default.nix b/libs/galley-types/default.nix index 2cbe283392e..5a6070c01a4 100644 --- a/libs/galley-types/default.nix +++ b/libs/galley-types/default.nix @@ -21,6 +21,7 @@ , tasty-quickcheck , text , types-common +, utf8-string , uuid , wire-api }: @@ -43,6 +44,7 @@ mkDerivation { schema-profunctor text types-common + utf8-string uuid wire-api ]; diff --git a/libs/galley-types/galley-types.cabal b/libs/galley-types/galley-types.cabal index 947ca36cd70..4953776a8ae 100644 --- a/libs/galley-types/galley-types.cabal +++ b/libs/galley-types/galley-types.cabal @@ -85,6 +85,7 @@ library , schema-profunctor , text >=0.11 , types-common >=0.16 + , utf8-string , uuid , wire-api diff --git a/libs/galley-types/src/Galley/Types.hs b/libs/galley-types/src/Galley/Types.hs index 8e035a40e02..b08103a22cd 100644 --- a/libs/galley-types/src/Galley/Types.hs +++ b/libs/galley-types/src/Galley/Types.hs @@ -26,7 +26,7 @@ where import Data.Aeson import Data.Id (ClientId, UserId) import Data.Map.Strict qualified as Map -import Imports hiding (cs) +import Imports import Wire.API.Message -------------------------------------------------------------------------------- diff --git a/libs/galley-types/src/Galley/Types/Teams.hs b/libs/galley-types/src/Galley/Types/Teams.hs index 07a2d755b4c..715377e42bb 100644 --- a/libs/galley-types/src/Galley/Types/Teams.hs +++ b/libs/galley-types/src/Galley/Types/Teams.hs @@ -62,6 +62,8 @@ where import Control.Lens (makeLenses, view) import Data.Aeson import Data.Aeson.Types qualified as A +import Data.ByteString (toStrict) +import Data.ByteString.UTF8 qualified as UTF8 import Data.Id (UserId) import Data.Schema qualified as Schema import Data.Set qualified as Set @@ -199,7 +201,7 @@ instance ToJSON FeatureFlags where instance FromJSON FeatureSSO where parseJSON (String "enabled-by-default") = pure FeatureSSOEnabledByDefault parseJSON (String "disabled-by-default") = pure FeatureSSODisabledByDefault - parseJSON bad = fail $ "FeatureSSO: " <> cs (encode bad) + parseJSON bad = fail $ "FeatureSSO: " <> (UTF8.toString . toStrict . encode $ bad) instance ToJSON FeatureSSO where toJSON FeatureSSOEnabledByDefault = String "enabled-by-default" @@ -209,7 +211,7 @@ instance FromJSON FeatureLegalHold where parseJSON (String "disabled-permanently") = pure $ FeatureLegalHoldDisabledPermanently parseJSON (String "disabled-by-default") = pure $ FeatureLegalHoldDisabledByDefault parseJSON (String "whitelist-teams-and-implicit-consent") = pure FeatureLegalHoldWhitelistTeamsAndImplicitConsent - parseJSON bad = fail $ "FeatureLegalHold: " <> cs (encode bad) + parseJSON bad = fail $ "FeatureLegalHold: " <> (UTF8.toString . toStrict . encode $ bad) instance ToJSON FeatureLegalHold where toJSON FeatureLegalHoldDisabledPermanently = String "disabled-permanently" @@ -219,7 +221,7 @@ instance ToJSON FeatureLegalHold where instance FromJSON FeatureTeamSearchVisibilityAvailability where parseJSON (String "enabled-by-default") = pure FeatureTeamSearchVisibilityAvailableByDefault parseJSON (String "disabled-by-default") = pure FeatureTeamSearchVisibilityUnavailableByDefault - parseJSON bad = fail $ "FeatureSearchVisibility: " <> cs (encode bad) + parseJSON bad = fail $ "FeatureSearchVisibility: " <> (UTF8.toString . toStrict . encode $ bad) instance ToJSON FeatureTeamSearchVisibilityAvailability where toJSON FeatureTeamSearchVisibilityAvailableByDefault = String "enabled-by-default" diff --git a/libs/gundeck-types/src/Gundeck/Types/Push/V2.hs b/libs/gundeck-types/src/Gundeck/Types/Push/V2.hs index aedfc7f0164..c087d911135 100644 --- a/libs/gundeck-types/src/Gundeck/Types/Push/V2.hs +++ b/libs/gundeck-types/src/Gundeck/Types/Push/V2.hs @@ -83,7 +83,7 @@ import Data.List1 qualified as List1 import Data.Range import Data.Range qualified as Range import Data.Set qualified as Set -import Imports hiding (cs) +import Imports import Wire.API.Message (Priority (..)) import Wire.API.Push.V2.Token import Wire.Arbitrary diff --git a/libs/imports/default.nix b/libs/imports/default.nix index b1b77f2c86e..728fca8f3b5 100644 --- a/libs/imports/default.nix +++ b/libs/imports/default.nix @@ -11,7 +11,6 @@ , gitignoreSource , lib , mtl -, string-conversions , text , transformers , unliftio @@ -29,7 +28,6 @@ mkDerivation { deepseq extra mtl - string-conversions text transformers unliftio diff --git a/libs/imports/imports.cabal b/libs/imports/imports.cabal index 845228c8f10..a1ddc13d9bb 100644 --- a/libs/imports/imports.cabal +++ b/libs/imports/imports.cabal @@ -75,7 +75,6 @@ library , deepseq , extra , mtl - , string-conversions , text , transformers , unliftio diff --git a/libs/imports/src/Imports.hs b/libs/imports/src/Imports.hs index d44ab47c404..91841bbdd8c 100644 --- a/libs/imports/src/Imports.hs +++ b/libs/imports/src/Imports.hs @@ -114,7 +114,6 @@ module Imports -- * Extra Helpers whenM, unlessM, - cs, -- * Functor (<$$>), @@ -165,7 +164,6 @@ import Data.Ord import Data.Semigroup hiding (diff) import Data.Set (Set) import Data.String -import Data.String.Conversions (cs) import Data.Text (Text) import Data.Text.Lazy qualified import Data.Traversable diff --git a/libs/jwt-tools/default.nix b/libs/jwt-tools/default.nix index a6cdf09b241..1314bde5186 100644 --- a/libs/jwt-tools/default.nix +++ b/libs/jwt-tools/default.nix @@ -12,7 +12,9 @@ , imports , lib , rusty_jwt_tools_ffi +, string-conversions , transformers +, utf8-string }: mkDerivation { pname = "jwt-tools"; @@ -24,9 +26,16 @@ mkDerivation { http-types imports transformers + utf8-string ]; librarySystemDepends = [ rusty_jwt_tools_ffi ]; - testHaskellDepends = [ bytestring hspec imports transformers ]; + testHaskellDepends = [ + bytestring + hspec + imports + string-conversions + transformers + ]; description = "FFI to rusty-jwt-tools"; license = lib.licenses.agpl3Only; } diff --git a/libs/jwt-tools/jwt-tools.cabal b/libs/jwt-tools/jwt-tools.cabal index 57f815466ab..e2f12a9b352 100644 --- a/libs/jwt-tools/jwt-tools.cabal +++ b/libs/jwt-tools/jwt-tools.cabal @@ -68,6 +68,7 @@ library , http-types , imports , transformers + , utf8-string default-language: GHC2021 other-extensions: ForeignFunctionInterface @@ -83,6 +84,7 @@ test-suite jwt-tools-tests , hspec , imports , jwt-tools + , string-conversions , transformers hs-source-dirs: test diff --git a/libs/jwt-tools/src/Data/Jwt/Tools.hs b/libs/jwt-tools/src/Data/Jwt/Tools.hs index a38cc02c9fd..e9c3ce549de 100644 --- a/libs/jwt-tools/src/Data/Jwt/Tools.hs +++ b/libs/jwt-tools/src/Data/Jwt/Tools.hs @@ -42,6 +42,7 @@ where import Control.Exception hiding (handle) import Control.Monad.Trans.Except import Data.ByteString.Conversion +import Data.ByteString.UTF8 qualified as UTF8 import Foreign.C.String (CString, newCString, peekCString) import Foreign.Ptr (Ptr, nullPtr) import Imports @@ -163,7 +164,7 @@ generateDpopToken dpopProof uid cid handle displayName tid domain nonce uri meth domainCStr <- toCStr domain nonceCStr <- toCStr nonce uriCStr <- toCStr uri - methodCStr <- liftIO $ newCString $ cs $ methodToBS method + methodCStr <- liftIO $ newCString $ UTF8.toString $ methodToBS method backendPubkeyBundleCStr <- toCStr backendPubkeyBundle -- log all variable inputs (can comment in if need to generate new test data) @@ -205,7 +206,7 @@ generateDpopToken dpopProof uid cid handle displayName tid domain nonce uri meth toCStr = liftIO . newCString . toStr where toStr :: a -> String - toStr = cs . toByteString' + toStr = UTF8.toString . toByteString' methodToBS :: StdMethod -> ByteString methodToBS = \case @@ -221,8 +222,8 @@ generateDpopToken dpopProof uid cid handle displayName tid domain nonce uri meth toResult :: Maybe Word8 -> Maybe String -> Either DPoPTokenGenerationError ByteString -- the only valid cases are when the error=0 (meaning no error) or nothing and the token is not null -toResult (Just 0) (Just token) = Right $ cs token -toResult Nothing (Just token) = Right $ cs token +toResult (Just 0) (Just token) = Right $ UTF8.fromString token +toResult Nothing (Just token) = Right $ UTF8.fromString token -- errors toResult (Just errNo) _ = Left $ fromInt (fromIntegral errNo) where diff --git a/libs/jwt-tools/test/Spec.hs b/libs/jwt-tools/test/Spec.hs index 2e0afb3dc13..664c18d3874 100644 --- a/libs/jwt-tools/test/Spec.hs +++ b/libs/jwt-tools/test/Spec.hs @@ -18,6 +18,7 @@ import Control.Monad.Trans.Except import Data.ByteString.Char8 (split) import Data.Jwt.Tools +import Data.String.Conversions import Imports import Test.Hspec diff --git a/libs/metrics-wai/default.nix b/libs/metrics-wai/default.nix index 616c581b7fd..eb65cf447ae 100644 --- a/libs/metrics-wai/default.nix +++ b/libs/metrics-wai/default.nix @@ -16,6 +16,7 @@ , servant , servant-multipart , text +, utf8-string , wai , wai-middleware-prometheus , wai-route @@ -35,6 +36,7 @@ mkDerivation { servant servant-multipart text + utf8-string wai wai-middleware-prometheus wai-route diff --git a/libs/metrics-wai/metrics-wai.cabal b/libs/metrics-wai/metrics-wai.cabal index 5ea237e1964..3d9725348fe 100644 --- a/libs/metrics-wai/metrics-wai.cabal +++ b/libs/metrics-wai/metrics-wai.cabal @@ -79,6 +79,7 @@ library , servant , servant-multipart , text >=0.11 + , utf8-string , wai >=3 , wai-middleware-prometheus , wai-route >=0.3 diff --git a/libs/metrics-wai/src/Data/Metrics/Servant.hs b/libs/metrics-wai/src/Data/Metrics/Servant.hs index 372cdc95055..b8ec0984997 100644 --- a/libs/metrics-wai/src/Data/Metrics/Servant.hs +++ b/libs/metrics-wai/src/Data/Metrics/Servant.hs @@ -26,11 +26,14 @@ -- | Given a servant API type, this module gives you a 'Paths' for 'withPathTemplate'. module Data.Metrics.Servant where +import Data.ByteString.UTF8 qualified as UTF8 import Data.Metrics.Middleware.Prometheus (normalizeWaiRequestRoute) import Data.Metrics.Types import Data.Metrics.Types qualified as Metrics import Data.Metrics.WaiRoute (treeToPaths) import Data.Proxy +import Data.Text.Encoding +import Data.Text.Encoding.Error import Data.Tree import GHC.TypeLits import Imports @@ -48,8 +51,8 @@ servantPrometheusMiddleware _ = Promth.prometheus conf . instrument promthNormal promthNormalize :: Wai.Request -> Text promthNormalize req = pathInfo where - mPathInfo = Metrics.treeLookup (routesToPaths @api) $ cs <$> Wai.pathInfo req - pathInfo = cs $ fromMaybe "N/A" mPathInfo + mPathInfo = Metrics.treeLookup (routesToPaths @api) $ encodeUtf8 <$> Wai.pathInfo req + pathInfo = decodeUtf8With lenientDecode $ fromMaybe "N/A" mPathInfo -- See Note [Raw Response] instrument = Promth.instrumentHandlerValueWithFilter Promth.ignoreRawResponses @@ -85,14 +88,14 @@ instance (KnownSymbol seg, RoutesToPaths segs) => RoutesToPaths (seg :> segs) where - getRoutes = [Node (Right . cs $ symbolVal (Proxy @seg)) (getRoutes @segs)] + getRoutes = [Node (Right . UTF8.fromString $ symbolVal (Proxy @seg)) (getRoutes @segs)] -- :> routes instance (KnownSymbol capture, RoutesToPaths segs) => RoutesToPaths (Capture' mods capture a :> segs) where - getRoutes = [Node (Left (cs (":" <> symbolVal (Proxy @capture)))) (getRoutes @segs)] + getRoutes = [Node (Left (UTF8.fromString (":" <> symbolVal (Proxy @capture)))) (getRoutes @segs)] instance (RoutesToPaths rest) => diff --git a/libs/metrics-wai/src/Data/Metrics/Test.hs b/libs/metrics-wai/src/Data/Metrics/Test.hs index 308dc18193f..95016f23a5f 100644 --- a/libs/metrics-wai/src/Data/Metrics/Test.hs +++ b/libs/metrics-wai/src/Data/Metrics/Test.hs @@ -19,6 +19,8 @@ module Data.Metrics.Test where import Data.Metrics.Types import Data.Text qualified as Text +import Data.Text.Encoding +import Data.Text.Encoding.Error import Data.Tree qualified as Tree import Imports @@ -50,9 +52,12 @@ pathsConsistencyCheck (Paths forest) = mconcat $ go [] <$> forest findSiteConsistencyError prefix subtrees = case mapMaybe captureVars subtrees of [] -> Nothing [_] -> Nothing - bad@(_ : _ : _) -> Just $ SiteConsistencyError (either cs cs <$> prefix) bad + bad@(_ : _ : _) -> + Just $ + SiteConsistencyError (either decode decode <$> prefix) bad captureVars :: Tree.Tree (Either ByteString any) -> Maybe (Text, Int) - captureVars (Tree.Node (Left root) trees) = Just (cs root, weight trees) + captureVars (Tree.Node (Left root) trees) = Just (decode root, weight trees) captureVars (Tree.Node (Right _) _) = Nothing weight :: Tree.Forest a -> Int weight = sum . fmap (length . Tree.flatten) + decode = decodeUtf8With lenientDecode diff --git a/libs/polysemy-wire-zoo/src/Wire/Sem/Jwk.hs b/libs/polysemy-wire-zoo/src/Wire/Sem/Jwk.hs index c0edb3d94c4..913e5cbf7b7 100644 --- a/libs/polysemy-wire-zoo/src/Wire/Sem/Jwk.hs +++ b/libs/polysemy-wire-zoo/src/Wire/Sem/Jwk.hs @@ -5,6 +5,7 @@ module Wire.Sem.Jwk where import Control.Exception import Crypto.JOSE.JWK import Data.Aeson +import Data.ByteString (fromStrict) import qualified Data.ByteString as BS import Imports import Polysemy @@ -18,4 +19,8 @@ interpretJwk :: Members '[Embed IO] r => Sem (Jwk ': r) a -> Sem r a interpretJwk = interpret $ \(Get fp) -> liftIO $ readJwk fp readJwk :: FilePath -> IO (Maybe JWK) -readJwk fp = try @IOException (BS.readFile fp) <&> either (const Nothing) (decode . cs) +readJwk fp = + try @IOException (BS.readFile fp) + <&> either + (const Nothing) + (decode . fromStrict) diff --git a/libs/types-common/default.nix b/libs/types-common/default.nix index abf2ee2f27d..7421aae499c 100644 --- a/libs/types-common/default.nix +++ b/libs/types-common/default.nix @@ -41,6 +41,7 @@ , random , schema-profunctor , servant-server +, string-conversions , tagged , tasty , tasty-hunit @@ -52,6 +53,7 @@ , unix , unordered-containers , uri-bytestring +, utf8-string , uuid , yaml }: @@ -105,6 +107,7 @@ mkDerivation { unix unordered-containers uri-bytestring + utf8-string uuid yaml ]; @@ -116,6 +119,7 @@ mkDerivation { cereal imports protobuf + string-conversions tasty tasty-hunit tasty-quickcheck diff --git a/libs/types-common/src/Data/Code.hs b/libs/types-common/src/Data/Code.hs index c745b752caa..ef70a0aeb52 100644 --- a/libs/types-common/src/Data/Code.hs +++ b/libs/types-common/src/Data/Code.hs @@ -35,7 +35,8 @@ import Data.Range import Data.Schema import Data.Text (pack) import Data.Text.Ascii -import Data.Text.Encoding (encodeUtf8) +import Data.Text.Encoding +import Data.Text.Encoding.Error import Data.Time.Clock import Imports import Servant (FromHttpApiData (..), ToHttpApiData (..)) @@ -62,7 +63,7 @@ instance FromHttpApiData Key where first pack $ runParser parser (encodeUtf8 s) instance ToHttpApiData Key where - toQueryParam key = cs (toByteString' key) + toQueryParam key = decodeUtf8With lenientDecode (toByteString' key) -- | A secret value bound to a 'Key' and a 'Timeout'. newtype Value = Value {asciiValue :: Range 6 20 AsciiBase64Url} @@ -85,7 +86,7 @@ instance FromHttpApiData Value where first pack $ runParser parser (encodeUtf8 s) instance ToHttpApiData Value where - toQueryParam key = cs (toByteString' key) + toQueryParam key = decodeUtf8With lenientDecode (toByteString' key) -- | A 'Timeout' is rendered in/parsed from JSON as an integer representing the -- number of seconds remaining. diff --git a/libs/types-common/src/Data/Domain.hs b/libs/types-common/src/Data/Domain.hs index e45d966c85b..ed74cd230a3 100644 --- a/libs/types-common/src/Data/Domain.hs +++ b/libs/types-common/src/Data/Domain.hs @@ -82,7 +82,7 @@ instance FromByteString Domain where parser = domainParser instance ToByteString Domain where - builder = Builder.lazyByteString . cs @Text @LByteString . _domainText + builder = Builder.lazyByteString . BS.Char8.fromStrict . Text.E.encodeUtf8 . _domainText instance FromHttpApiData Domain where parseUrlPiece = first Text.pack . mkDomain diff --git a/libs/types-common/src/Data/Json/Util.hs b/libs/types-common/src/Data/Json/Util.hs index f6c990081ec..91f0e420fe6 100644 --- a/libs/types-common/src/Data/Json/Util.hs +++ b/libs/types-common/src/Data/Json/Util.hs @@ -61,6 +61,7 @@ import Data.ByteString.Base64.URL qualified as B64U import Data.ByteString.Builder qualified as BB import Data.ByteString.Conversion qualified as BS import Data.ByteString.Lazy qualified as L +import Data.ByteString.UTF8 qualified as UTF8 import Data.Fixed import Data.OpenApi qualified as S import Data.Schema @@ -141,7 +142,7 @@ instance Show UTCTimeMillis where showsPrec d = showParen (d > 10) . showString . Text.unpack . showUTCTimeMillis instance BS.ToByteString UTCTimeMillis where - builder = BB.byteString . cs . show + builder = BB.byteString . UTF8.fromString . show instance BS.FromByteString UTCTimeMillis where parser = maybe (fail "UTCTimeMillis") pure . readUTCTimeMillis =<< BS.parser diff --git a/libs/types-common/src/Data/Misc.hs b/libs/types-common/src/Data/Misc.hs index 23a404e2c02..837c24d18c2 100644 --- a/libs/types-common/src/Data/Misc.hs +++ b/libs/types-common/src/Data/Misc.hs @@ -79,7 +79,8 @@ import Data.OpenApi qualified as S import Data.Range import Data.Schema import Data.Text qualified as Text -import Data.Text.Encoding (decodeUtf8, encodeUtf8) +import Data.Text.Encoding +import Data.Text.Encoding.Error import GHC.TypeLits (Nat) import GHC.TypeNats (KnownNat) import Imports @@ -139,10 +140,13 @@ instance ToSchema IpAddr where schema = toText .= parsedText "IpAddr" fromText where toText :: IpAddr -> Text - toText = cs . toByteString + toText = decodeUtf8With lenientDecode . toStrict . toByteString fromText :: Text -> Either String IpAddr - fromText = maybe (Left "Failed parsing IP address.") Right . fromByteString . cs + fromText = + maybe (Left "Failed parsing IP address.") Right + . fromByteString + . encodeUtf8 instance ToSchema Port where schema = Port <$> portNumber .= schema diff --git a/libs/types-common/src/Data/Nonce.hs b/libs/types-common/src/Data/Nonce.hs index 1f094bab764..50d84f7c655 100644 --- a/libs/types-common/src/Data/Nonce.hs +++ b/libs/types-common/src/Data/Nonce.hs @@ -35,6 +35,8 @@ import Data.OpenApi qualified as S import Data.OpenApi.ParamSchema import Data.Proxy (Proxy (Proxy)) import Data.Schema +import Data.Text.Encoding +import Data.Text.Encoding.Error import Data.UUID as UUID (UUID, fromByteString, toByteString) import Data.UUID.V4 (nextRandom) import Imports @@ -48,10 +50,15 @@ newtype Nonce = Nonce {unNonce :: UUID} deriving (A.FromJSON, A.ToJSON, S.ToSchema) via (Schema Nonce) instance ToSchema Nonce where - schema = (cs . toByteString') .= parsedText "Nonce" p + schema = + (decodeUtf8With lenientDecode . toByteString') .= parsedText "Nonce" p where p :: Text -> Either String Nonce - p = maybe (Left "Invalid Nonce") Right . fromByteString' . cs + p = + maybe (Left "Invalid Nonce") Right + . fromByteString' + . fromStrict + . encodeUtf8 instance ToByteString Nonce where builder = builder . Base64.encodeUnpadded . toStrict . UUID.toByteString . unNonce @@ -68,16 +75,20 @@ instance ToParamSchema Nonce where toParamSchema _ = toParamSchema (Proxy @Text) instance ToHttpApiData Nonce where - toQueryParam = cs . toByteString' + toQueryParam = decodeUtf8With lenientDecode . toByteString' instance FromHttpApiData Nonce where - parseQueryParam = maybe (Left "Invalid Nonce") Right . fromByteString' . cs + parseQueryParam = + maybe (Left "Invalid Nonce") Right + . fromByteString' + . fromStrict + . encodeUtf8 randomNonce :: MonadIO m => m Nonce randomNonce = Nonce <$> liftIO nextRandom isValidBase64UrlEncodedUUID :: ByteString -> Bool -isValidBase64UrlEncodedUUID = isJust . fromByteString' @Nonce . cs +isValidBase64UrlEncodedUUID = isJust . fromByteString' @Nonce . fromStrict instance Cql Nonce where ctype = Tagged UuidColumn diff --git a/libs/types-common/src/Util/Logging.hs b/libs/types-common/src/Util/Logging.hs index 0b4a3e7c5a2..318785c7578 100644 --- a/libs/types-common/src/Util/Logging.hs +++ b/libs/types-common/src/Util/Logging.hs @@ -29,7 +29,7 @@ import System.Logger.Message (Msg) sha256String :: Text -> Text sha256String t = let digest = hash @ByteString @SHA256 (encodeUtf8 t) - in cs . show $ digest + in T.pack . show $ digest logHandle :: Handle -> (Msg -> Msg) logHandle handl = @@ -44,7 +44,7 @@ logFunction fn = Log.field "fn" fn . Log.field "module" (getModule fn) x -> T.intercalate "." (init x) logUser :: UserId -> (Msg -> Msg) -logUser uid = Log.field "user" (cs @_ @Text . show $ uid) +logUser uid = Log.field "user" (T.pack . show $ uid) logTeam :: TeamId -> (Msg -> Msg) -logTeam tid = Log.field "team" (cs @_ @Text . show $ tid) +logTeam tid = Log.field "team" (T.pack . show $ tid) diff --git a/libs/types-common/test/Test/Data/PEMKeys.hs b/libs/types-common/test/Test/Data/PEMKeys.hs index 013688d7d70..c7a727f23d1 100644 --- a/libs/types-common/test/Test/Data/PEMKeys.hs +++ b/libs/types-common/test/Test/Data/PEMKeys.hs @@ -22,6 +22,7 @@ where import Data.ByteString.Conversion import Data.PEMKeys +import Data.String.Conversions import Imports import Test.Tasty import Test.Tasty.HUnit diff --git a/libs/types-common/test/Test/Properties.hs b/libs/types-common/test/Test/Properties.hs index 8e0556df41d..fbd1de60122 100644 --- a/libs/types-common/test/Test/Properties.hs +++ b/libs/types-common/test/Test/Properties.hs @@ -39,6 +39,7 @@ import Data.Json.Util qualified as Util import Data.Nonce (Nonce) import Data.ProtocolBuffers.Internal import Data.Serialize +import Data.String.Conversions import Data.Text.Ascii import Data.Text.Ascii qualified as Ascii import Data.Time diff --git a/libs/types-common/types-common.cabal b/libs/types-common/types-common.cabal index 14cb8cb6a6a..5fb1c0ca72c 100644 --- a/libs/types-common/types-common.cabal +++ b/libs/types-common/types-common.cabal @@ -136,6 +136,7 @@ library , unix , unordered-containers >=0.2 , uri-bytestring >=0.2 + , utf8-string , uuid >=1.3.11 , yaml >=0.8.22 @@ -209,6 +210,7 @@ test-suite tests , cereal , imports , protobuf + , string-conversions , tasty , tasty-hunit , tasty-quickcheck diff --git a/libs/wai-utilities/src/Network/Wai/Utilities/Headers.hs b/libs/wai-utilities/src/Network/Wai/Utilities/Headers.hs index f1673e7de13..56049d0ecdf 100644 --- a/libs/wai-utilities/src/Network/Wai/Utilities/Headers.hs +++ b/libs/wai-utilities/src/Network/Wai/Utilities/Headers.hs @@ -17,9 +17,12 @@ module Network.Wai.Utilities.Headers where +import Data.ByteString import Data.ByteString.Conversion (FromByteString (..), ToByteString (..), fromByteString', toByteString') import Data.OpenApi.ParamSchema (ToParamSchema (..)) import Data.Text as T +import Data.Text.Encoding +import Data.Text.Encoding.Error import Imports import Servant (FromHttpApiData (..), Proxy (Proxy), ToHttpApiData (..)) @@ -37,10 +40,14 @@ instance FromByteString CacheControl where _ -> fail $ "Invalid CacheControl type: " ++ show t instance ToHttpApiData CacheControl where - toQueryParam = cs . toByteString' + toQueryParam = decodeUtf8With lenientDecode . toByteString' instance FromHttpApiData CacheControl where - parseQueryParam = maybe (Left "Invalid CacheControl") Right . fromByteString' . cs + parseQueryParam = + maybe (Left "Invalid CacheControl") Right + . fromByteString' + . fromStrict + . encodeUtf8 instance ToParamSchema CacheControl where toParamSchema _ = toParamSchema (Proxy @Text) diff --git a/libs/wai-utilities/src/Network/Wai/Utilities/Server.hs b/libs/wai-utilities/src/Network/Wai/Utilities/Server.hs index e611a3e34fd..80ee4329c13 100644 --- a/libs/wai-utilities/src/Network/Wai/Utilities/Server.hs +++ b/libs/wai-utilities/src/Network/Wai/Utilities/Server.hs @@ -52,6 +52,7 @@ import Control.Error.Util ((?:)) import Control.Exception (throw) import Control.Monad.Catch hiding (onError, onException) import Data.Aeson (decode, encode) +import Data.ByteString (toStrict) import Data.ByteString qualified as BS import Data.ByteString.Builder import Data.ByteString.Char8 qualified as C @@ -61,6 +62,7 @@ import Data.Metrics.GC (spawnGCMetricsCollector) import Data.Metrics.Middleware import Data.Streaming.Zlib (ZlibException (..)) import Data.Text.Encoding.Error (lenientDecode) +import Data.Text.Lazy qualified as LT import Data.Text.Lazy.Encoding qualified as LT import Imports import Network.HTTP.Types.Status @@ -222,7 +224,7 @@ errorHandlers = Wai.mkError status500 "server-error" "Server Error", Handler $ \(e :: SomeException) -> pure . Left $ - Wai.mkError status500 "server-error" ("Server Error. " <> cs (displayException e)) + Wai.mkError status500 "server-error" ("Server Error. " <> LT.pack (displayException e)) ] {-# INLINE errorHandlers #-} @@ -290,7 +292,7 @@ heavyDebugLogging sanitizeReq lvl lgr app = \req cont -> do -- >>> pure $ fromMaybe "" nextChunk emitLByteString :: LByteString -> IO (IO ByteString) emitLByteString lbs = do - tvar <- newTVarIO (cs lbs) + tvar <- newTVarIO (toStrict lbs) -- Emit the bytestring on the first read, then always return "" on subsequent reads pure . atomically $ swapTVar tvar mempty @@ -323,7 +325,7 @@ rethrow5xx logger app req k = app req k' wrapError :: Status -> LByteString -> Wai.Error wrapError st body = decode body ?: - Wai.mkError st "server-error" (cs body) + Wai.mkError st "server-error" (LT.decodeUtf8With lenientDecode body) -- | This flushes the response! If you want to keep using the response, you need to construct -- a new one with a fresh body stream. diff --git a/libs/wire-api-federation/src/Wire/API/Federation/Error.hs b/libs/wire-api-federation/src/Wire/API/Federation/Error.hs index 2303d744abb..830a9f062fc 100644 --- a/libs/wire-api-federation/src/Wire/API/Federation/Error.hs +++ b/libs/wire-api-federation/src/Wire/API/Federation/Error.hs @@ -245,7 +245,9 @@ federationRemoteHTTP2Error target path = \case addErrData err = err { Wai.errorData = - ((mkDomain . cs . srvTargetDomain $ target) :: Either String Domain) + ( (mkDomain . T.decodeUtf8With T.lenientDecode . srvTargetDomain $ target) :: + Either String Domain + ) & either (const Nothing) (\dom -> Just (Wai.FederationErrorData dom path)) } @@ -271,7 +273,9 @@ federationRemoteResponseError target path status body = ) ) { Wai.errorData = - ((mkDomain . cs . srvTargetDomain $ target) :: Either String Domain) + ( (mkDomain . T.decodeUtf8With T.lenientDecode . srvTargetDomain $ target) :: + Either String Domain + ) & either (const Nothing) (\dom -> Just (Wai.FederationErrorData dom path)), Wai.innerError = Just $ diff --git a/libs/wire-api/default.nix b/libs/wire-api/default.nix index 581ac8b9612..b3c02ca5099 100644 --- a/libs/wire-api/default.nix +++ b/libs/wire-api/default.nix @@ -86,6 +86,7 @@ , singletons-base , singletons-th , sop-core +, string-conversions , tagged , tasty , tasty-hspec @@ -244,6 +245,7 @@ mkDerivation { schema-profunctor servant servant-server + string-conversions tasty tasty-hspec tasty-hunit diff --git a/libs/wire-api/src/Wire/API/Call/Config.hs b/libs/wire-api/src/Wire/API/Call/Config.hs index 442f81fd4af..a4eb530ae5c 100644 --- a/libs/wire-api/src/Wire/API/Call/Config.hs +++ b/libs/wire-api/src/Wire/API/Call/Config.hs @@ -93,6 +93,7 @@ import Data.Aeson qualified as A hiding (()) import Data.Aeson.Types qualified as A import Data.Attoparsec.Text hiding (Parser, parse) import Data.Attoparsec.Text qualified as Text +import Data.ByteString (toStrict) import Data.ByteString.Builder import Data.ByteString.Conversion (toByteString) import Data.ByteString.Conversion qualified as BC @@ -104,6 +105,7 @@ import Data.Schema import Data.Text qualified as Text import Data.Text.Ascii import Data.Text.Encoding qualified as TE +import Data.Text.Encoding.Error import Data.Text.Strict.Lens (utf8) import Data.Time.Clock.POSIX import Imports @@ -264,7 +266,9 @@ data TurnURI = TurnURI deriving (A.ToJSON, A.FromJSON, S.ToSchema) via (Schema TurnURI) instance ToSchema TurnURI where - schema = (cs . toByteString) .= parsedText "TurnURI" parseTurnURI + schema = + (TE.decodeUtf8With lenientDecode . toStrict . toByteString) + .= parsedText "TurnURI" parseTurnURI turnURI :: Scheme -> TurnHost -> Port -> Maybe Transport -> TurnURI turnURI = TurnURI @@ -478,7 +482,7 @@ instance ToSchema SFTUsername where fromText = parseOnly (parseSFTUsername <* endOfInput) toText :: SFTUsername -> Text - toText = cs . toByteString + toText = TE.decodeUtf8With lenientDecode . toStrict . toByteString instance BC.ToByteString SFTUsername where builder su = @@ -555,7 +559,7 @@ instance ToSchema TurnUsername where fromText = parseOnly (parseTurnUsername <* endOfInput) toText :: TurnUsername -> Text - toText = cs . toByteString + toText = TE.decodeUtf8With lenientDecode . toStrict . toByteString instance BC.ToByteString TurnUsername where builder tu = diff --git a/libs/wire-api/src/Wire/API/Conversation.hs b/libs/wire-api/src/Wire/API/Conversation.hs index 84cd7d2390b..120ffe6a921 100644 --- a/libs/wire-api/src/Wire/API/Conversation.hs +++ b/libs/wire-api/src/Wire/API/Conversation.hs @@ -104,6 +104,7 @@ import Data.Range (Range, fromRange, rangedSchema) import Data.SOP import Data.Schema import Data.Set qualified as Set +import Data.Text qualified as Text import Data.UUID qualified as UUID import Data.UUID.V5 qualified as UUIDV5 import Imports @@ -724,7 +725,7 @@ newConvSchema sch = \to be part of this conversation" usersRoleDesc :: Text usersRoleDesc = - cs $ + Text.pack $ "The conversation permissions the users \ \added in this request should have. \ \Optional, defaults to '" diff --git a/libs/wire-api/src/Wire/API/Internal/Notification.hs b/libs/wire-api/src/Wire/API/Internal/Notification.hs index 849c8125460..7d43ef30962 100644 --- a/libs/wire-api/src/Wire/API/Internal/Notification.hs +++ b/libs/wire-api/src/Wire/API/Internal/Notification.hs @@ -47,7 +47,7 @@ import Data.Id import Data.List1 import Data.OpenApi qualified as Swagger import Data.Schema qualified as S -import Imports hiding (cs) +import Imports import Wire.API.Notification ------------------------------------------------------------------------------- diff --git a/libs/wire-api/src/Wire/API/MLS/AuthenticatedContent.hs b/libs/wire-api/src/Wire/API/MLS/AuthenticatedContent.hs index 521217f7c53..394a18ede1a 100644 --- a/libs/wire-api/src/Wire/API/MLS/AuthenticatedContent.hs +++ b/libs/wire-api/src/Wire/API/MLS/AuthenticatedContent.hs @@ -25,7 +25,7 @@ module Wire.API.MLS.AuthenticatedContent where import Crypto.PubKey.Ed25519 -import Imports hiding (cs) +import Imports import Wire.API.MLS.CipherSuite import Wire.API.MLS.Context import Wire.API.MLS.Epoch diff --git a/libs/wire-api/src/Wire/API/MLS/CipherSuite.hs b/libs/wire-api/src/Wire/API/MLS/CipherSuite.hs index f4e24df2989..32073718892 100644 --- a/libs/wire-api/src/Wire/API/MLS/CipherSuite.hs +++ b/libs/wire-api/src/Wire/API/MLS/CipherSuite.hs @@ -68,7 +68,7 @@ import Data.Text.Lazy qualified as LT import Data.Text.Lazy.Builder qualified as LT import Data.Text.Lazy.Builder.Int qualified as LT import Data.Word -import Imports hiding (cs) +import Imports import Web.HttpApiData import Wire.API.MLS.Serialisation import Wire.Arbitrary diff --git a/libs/wire-api/src/Wire/API/MLS/Group/Serialisation.hs b/libs/wire-api/src/Wire/API/MLS/Group/Serialisation.hs index 9a52f1a0879..3250af2f81a 100644 --- a/libs/wire-api/src/Wire/API/MLS/Group/Serialisation.hs +++ b/libs/wire-api/src/Wire/API/MLS/Group/Serialisation.hs @@ -35,7 +35,7 @@ import Data.Qualified import Data.Text qualified as T import Data.Text.Encoding qualified as T import Data.UUID qualified as UUID -import Imports hiding (cs) +import Imports import Web.HttpApiData (FromHttpApiData (parseHeader)) import Wire.API.Conversation import Wire.API.MLS.Group diff --git a/libs/wire-api/src/Wire/API/MLS/KeyPackage.hs b/libs/wire-api/src/Wire/API/MLS/KeyPackage.hs index 906ec74fc58..eb736de6ea5 100644 --- a/libs/wire-api/src/Wire/API/MLS/KeyPackage.hs +++ b/libs/wire-api/src/Wire/API/MLS/KeyPackage.hs @@ -49,7 +49,7 @@ import Data.Text qualified as T import Data.Text.Encoding qualified as T import Data.X509 qualified as X509 import GHC.Records -import Imports hiding (cs) +import Imports import Test.QuickCheck import Web.HttpApiData import Wire.API.MLS.CipherSuite diff --git a/libs/wire-api/src/Wire/API/MLS/Message.hs b/libs/wire-api/src/Wire/API/MLS/Message.hs index c13dcc0d96f..342bb739e23 100644 --- a/libs/wire-api/src/Wire/API/MLS/Message.hs +++ b/libs/wire-api/src/Wire/API/MLS/Message.hs @@ -45,7 +45,7 @@ import Data.Json.Util import Data.OpenApi qualified as S import Data.Schema hiding (HasField) import GHC.Records -import Imports hiding (cs) +import Imports import Test.QuickCheck hiding (label) import Wire.API.Event.Conversation import Wire.API.MLS.CipherSuite diff --git a/libs/wire-api/src/Wire/API/MLS/Proposal.hs b/libs/wire-api/src/Wire/API/MLS/Proposal.hs index 125364b8362..1ae2ef989ac 100644 --- a/libs/wire-api/src/Wire/API/MLS/Proposal.hs +++ b/libs/wire-api/src/Wire/API/MLS/Proposal.hs @@ -25,7 +25,7 @@ import Control.Lens (makePrisms) import Data.Binary import Data.ByteString as B import GHC.Records -import Imports hiding (cs) +import Imports import Test.QuickCheck import Wire.API.MLS.CipherSuite import Wire.API.MLS.Extension diff --git a/libs/wire-api/src/Wire/API/MLS/SubConversation.hs b/libs/wire-api/src/Wire/API/MLS/SubConversation.hs index c01aa3e2366..043984800ac 100644 --- a/libs/wire-api/src/Wire/API/MLS/SubConversation.hs +++ b/libs/wire-api/src/Wire/API/MLS/SubConversation.hs @@ -35,7 +35,7 @@ import Data.Schema hiding (HasField) import Data.Text qualified as T import Data.Time.Clock import GHC.Records -import Imports hiding (cs) +import Imports import Servant (FromHttpApiData (..), ToHttpApiData (toQueryParam)) import Test.QuickCheck import Wire.API.MLS.CipherSuite diff --git a/libs/wire-api/src/Wire/API/MLS/Validation.hs b/libs/wire-api/src/Wire/API/MLS/Validation.hs index 2f98d969426..b256f846632 100644 --- a/libs/wire-api/src/Wire/API/MLS/Validation.hs +++ b/libs/wire-api/src/Wire/API/MLS/Validation.hs @@ -29,7 +29,7 @@ import Data.Text.Lazy qualified as LT import Data.Text.Lazy.Builder qualified as LT import Data.Text.Lazy.Builder.Int qualified as LT import Data.X509 qualified as X509 -import Imports hiding (cs) +import Imports import Wire.API.MLS.Capabilities import Wire.API.MLS.CipherSuite import Wire.API.MLS.Credential diff --git a/libs/wire-api/src/Wire/API/MLS/Welcome.hs b/libs/wire-api/src/Wire/API/MLS/Welcome.hs index 08028e31219..8cf1839e9d5 100644 --- a/libs/wire-api/src/Wire/API/MLS/Welcome.hs +++ b/libs/wire-api/src/Wire/API/MLS/Welcome.hs @@ -18,7 +18,7 @@ module Wire.API.MLS.Welcome where import Data.OpenApi qualified as S -import Imports hiding (cs) +import Imports import Wire.API.MLS.CipherSuite import Wire.API.MLS.Commit import Wire.API.MLS.KeyPackage diff --git a/libs/wire-api/src/Wire/API/Notification.hs b/libs/wire-api/src/Wire/API/Notification.hs index 1b7601bce10..83317eb5259 100644 --- a/libs/wire-api/src/Wire/API/Notification.hs +++ b/libs/wire-api/src/Wire/API/Notification.hs @@ -51,6 +51,7 @@ import Data.OpenApi (ToParamSchema (..)) import Data.OpenApi qualified as S import Data.SOP import Data.Schema +import Data.Text.Encoding import Data.Time.Clock (UTCTime) import Data.UUID qualified as UUID import Imports @@ -150,7 +151,7 @@ newtype RawNotificationId = RawNotificationId {unRawNotificationId :: ByteString deriving stock (Eq, Show, Generic) instance FromHttpApiData RawNotificationId where - parseUrlPiece = pure . RawNotificationId . cs + parseUrlPiece = pure . RawNotificationId . encodeUtf8 instance ToParamSchema RawNotificationId where toParamSchema _ = toParamSchema (Proxy @Text) diff --git a/libs/wire-api/src/Wire/API/OAuth.hs b/libs/wire-api/src/Wire/API/OAuth.hs index 8b0a8617ad3..dfbd5987201 100644 --- a/libs/wire-api/src/Wire/API/OAuth.hs +++ b/libs/wire-api/src/Wire/API/OAuth.hs @@ -26,7 +26,7 @@ import Data.Aeson.KeyMap qualified as M import Data.Aeson.Types qualified as A import Data.ByteArray (convert) import Data.ByteString.Conversion -import Data.ByteString.Lazy (toStrict) +import Data.ByteString.Lazy (fromStrict, toStrict) import Data.Either.Combinators (mapLeft) import Data.HashMap.Strict qualified as HM import Data.Id as Id @@ -115,8 +115,8 @@ instance ToSchema OAuthClientConfig where where applicationNameDescription = description ?~ "The name of the application. This will be shown to the user when they are asked to authorize the application. The name must be between " <> minL <> " and " <> maxL <> " characters long." redirectUrlDescription = description ?~ "The URL to redirect to after the user has authorized the application." - minL = cs @String @Text $ symbolVal $ Proxy @(Show_ OAuthApplicationNameMinLength) - maxL = cs @String @Text $ symbolVal $ Proxy @(Show_ OAuthApplicationNameMaxLength) + minL = T.pack $ symbolVal $ Proxy @(Show_ OAuthApplicationNameMinLength) + maxL = T.pack $ symbolVal $ Proxy @(Show_ OAuthApplicationNameMaxLength) newtype OAuthClientPlainTextSecret = OAuthClientPlainTextSecret {unOAuthClientPlainTextSecret :: AsciiBase16} deriving (Eq, Generic, Arbitrary) @@ -130,7 +130,7 @@ instance ToSchema OAuthClientPlainTextSecret where schema = (toText . unOAuthClientPlainTextSecret) .= parsedText "OAuthClientPlainTextSecret" (fmap OAuthClientPlainTextSecret . validateBase16) instance FromHttpApiData OAuthClientPlainTextSecret where - parseQueryParam = bimap cs OAuthClientPlainTextSecret . validateBase16 . cs + parseQueryParam = bimap T.pack OAuthClientPlainTextSecret . validateBase16 instance ToHttpApiData OAuthClientPlainTextSecret where toQueryParam = toText . unOAuthClientPlainTextSecret @@ -236,11 +236,17 @@ instance ToSchema OAuthScopes where schema = OAuthScopes <$> (oauthScopesToText . unOAuthScopes) .= withParser schema oauthScopeParser where oauthScopesToText :: Set OAuthScope -> Text - oauthScopesToText = T.intercalate " " . fmap (cs . toByteString') . Set.toList + oauthScopesToText = + T.intercalate " " + . fmap (TE.decodeUtf8With lenientDecode . toByteString') + . Set.toList oauthScopeParser :: Text -> A.Parser (Set OAuthScope) oauthScopeParser scope = - pure $ (not . T.null) `filter` T.splitOn " " scope & maybe Set.empty Set.fromList . mapM (fromByteString' . cs) + pure $ + (not . T.null) `filter` T.splitOn " " scope + & maybe Set.empty Set.fromList + . mapM (fromByteString' . fromStrict . TE.encodeUtf8) data CodeChallengeMethod = S256 deriving (Eq, Show, Generic) @@ -265,7 +271,7 @@ instance ToSchema OAuthCodeVerifier where schema = OAuthCodeVerifier <$> unOAuthCodeVerifier .= schema instance FromHttpApiData OAuthCodeVerifier where - parseQueryParam = fmap OAuthCodeVerifier . mapLeft cs . checkedEither + parseQueryParam = fmap OAuthCodeVerifier . mapLeft T.pack . checkedEither instance ToHttpApiData OAuthCodeVerifier where toQueryParam = fromRange . unOAuthCodeVerifier @@ -294,7 +300,7 @@ mkChallenge = . encodeBase64UrlUnpadded . convert . Crypto.hash @ByteString @Crypto.SHA256 - . cs + . TE.encodeUtf8 . fromRange . unOAuthCodeVerifier @@ -347,7 +353,7 @@ instance FromByteString OAuthAuthorizationCode where parser = OAuthAuthorizationCode <$> parser instance FromHttpApiData OAuthAuthorizationCode where - parseQueryParam = bimap cs OAuthAuthorizationCode . validateBase16 . cs + parseQueryParam = bimap T.pack OAuthAuthorizationCode . validateBase16 instance ToHttpApiData OAuthAuthorizationCode where toQueryParam = toText . unOAuthAuthorizationCode @@ -379,10 +385,10 @@ instance ToByteString OAuthGrantType where OAuthGrantTypeRefreshToken -> "refresh_token" instance FromHttpApiData OAuthGrantType where - parseQueryParam = maybe (Left "invalid OAuthGrantType") pure . fromByteString . cs + parseQueryParam = maybe (Left "invalid OAuthGrantType") pure . fromByteString . TE.encodeUtf8 instance ToHttpApiData OAuthGrantType where - toQueryParam = cs . toByteString + toQueryParam = TE.decodeUtf8With lenientDecode . toStrict . toByteString data OAuthAccessTokenRequest = OAuthAccessTokenRequest { grantType :: OAuthGrantType, @@ -454,20 +460,27 @@ instance ToByteString (OAuthToken a) where instance FromByteString (OAuthToken a) where parser = do t <- parser @Text - case decodeCompact (cs (TE.encodeUtf8 t)) of + case decodeCompact (fromStrict (TE.encodeUtf8 t)) of Left (err :: JWTError) -> fail $ show err Right jwt -> pure $ OAuthToken jwt instance ToHttpApiData (OAuthToken a) where toHeader = toByteString' - toUrlPiece = cs . toHeader + toUrlPiece = TE.decodeUtf8With lenientDecode . toHeader instance FromHttpApiData (OAuthToken a) where - parseHeader = either (Left . cs) pure . runParser parser . cs - parseUrlPiece = parseHeader . cs + parseHeader = either (Left . T.pack) pure . runParser parser + parseUrlPiece = parseHeader . TE.encodeUtf8 instance ToSchema (OAuthToken a) where - schema = (TE.decodeUtf8 . toByteString') .= withParser schema (either fail pure . runParser parser . cs) + schema = + (TE.decodeUtf8 . toByteString') + .= withParser + schema + ( either fail pure + . runParser parser + . TE.encodeUtf8 + ) type OAuthAccessToken = OAuthToken 'Access @@ -686,8 +699,11 @@ instance Cql OAuthAuthorizationCode where instance Cql OAuthScope where ctype = Tagged TextColumn - toCql = CqlText . cs . toByteString' - fromCql (CqlText t) = maybe (Left "invalid oauth scope") Right $ fromByteString' (cs t) + toCql = CqlText . TE.decodeUtf8With lenientDecode . toByteString' + fromCql (CqlText t) = + maybe (Left "invalid oauth scope") Right $ + fromByteString' . fromStrict . TE.encodeUtf8 $ + t fromCql _ = Left "OAuthScope: Text expected" instance Cql OAuthCodeChallenge where diff --git a/libs/wire-api/src/Wire/API/Routes/MultiTablePaging/State.hs b/libs/wire-api/src/Wire/API/Routes/MultiTablePaging/State.hs index 7d43b3009be..1fae94b78b4 100644 --- a/libs/wire-api/src/Wire/API/Routes/MultiTablePaging/State.hs +++ b/libs/wire-api/src/Wire/API/Routes/MultiTablePaging/State.hs @@ -64,7 +64,9 @@ instance PagingTable tables => ToHttpApiData (MultiTablePagingState name tables) toQueryParam = (Text.decodeUtf8 . Base64Url.encode) . encodePagingState instance PagingTable tables => FromHttpApiData (MultiTablePagingState name tables) where - parseQueryParam = mapLeft cs . (parsePagingState <=< (Base64Url.decode . Text.encodeUtf8)) + parseQueryParam = + mapLeft Text.pack + . (parsePagingState <=< (Base64Url.decode . Text.encodeUtf8)) -- | A class for values that can be encoded with a single byte. Used to add a -- byte of extra information to the paging state in order to recover the table diff --git a/libs/wire-api/src/Wire/API/Routes/MultiVerb.hs b/libs/wire-api/src/Wire/API/Routes/MultiVerb.hs index ed24bbfdbe5..7c4e6dcd5ab 100644 --- a/libs/wire-api/src/Wire/API/Routes/MultiVerb.hs +++ b/libs/wire-api/src/Wire/API/Routes/MultiVerb.hs @@ -72,7 +72,7 @@ import Data.Text.Encoding qualified as Text import Data.Typeable import GHC.TypeLits import Generics.SOP as GSOP -import Imports hiding (cs) +import Imports import Network.HTTP.Media qualified as M import Network.HTTP.Types (hContentType) import Network.HTTP.Types qualified as HTTP diff --git a/libs/wire-api/src/Wire/API/Routes/Named.hs b/libs/wire-api/src/Wire/API/Routes/Named.hs index f76ada19664..5e8220818b5 100644 --- a/libs/wire-api/src/Wire/API/Routes/Named.hs +++ b/libs/wire-api/src/Wire/API/Routes/Named.hs @@ -25,6 +25,7 @@ import Data.Metrics.Servant import Data.OpenApi.Lens hiding (HasServer) import Data.OpenApi.Operation import Data.Proxy +import Data.Text qualified as T import GHC.TypeLits import Imports import Servant @@ -42,7 +43,7 @@ class RenderableSymbol a where renderSymbol :: Text instance {-# OVERLAPPABLE #-} KnownSymbol a => RenderableSymbol a where - renderSymbol = cs . show $ symbolVal (Proxy @a) + renderSymbol = T.pack . show $ symbolVal (Proxy @a) instance {-# OVERLAPPING #-} (RenderableSymbol a, RenderableSymbol b) => RenderableSymbol '(a, b) where renderSymbol = "(" <> (renderSymbol @a) <> ", " <> (renderSymbol @b) <> ")" @@ -55,7 +56,7 @@ instance (HasOpenApi api, RenderableSymbol name) => HasOpenApi (Named name api) dscr :: Text dscr = " [internal route ID: " - <> cs (renderSymbol @name) + <> renderSymbol @name <> "]" instance HasServer api ctx => HasServer (Named name api) ctx where diff --git a/libs/wire-api/src/Wire/API/Routes/Public.hs b/libs/wire-api/src/Wire/API/Routes/Public.hs index f5dd0fd40fa..73b6de1b3f6 100644 --- a/libs/wire-api/src/Wire/API/Routes/Public.hs +++ b/libs/wire-api/src/Wire/API/Routes/Public.hs @@ -39,6 +39,7 @@ module Wire.API.Routes.Public where import Control.Lens ((%~), (<>~)) +import Data.ByteString (toStrict) import Data.ByteString.Conversion (toByteString) import Data.Domain import Data.HashMap.Strict.InsOrd qualified as InsOrdHashMap @@ -48,6 +49,8 @@ import Data.Metrics.Servant import Data.OpenApi hiding (HasServer, Header, Server) import Data.OpenApi qualified as S import Data.Qualified +import Data.Text.Encoding +import Data.Text.Encoding.Error import GHC.Base (Symbol) import GHC.TypeLits (KnownSymbol) import Imports hiding (All, head) @@ -339,7 +342,18 @@ instance toOpenApi _ = addScopeDescription @scope (toOpenApi (Proxy @api)) addScopeDescription :: forall scope. OAuth.IsOAuthScope scope => OpenApi -> OpenApi -addScopeDescription = allOperations . description %~ Just . (<> "\nOAuth scope: `" <> cs (toByteString (OAuth.toOAuthScope @scope)) <> "`") . fold +addScopeDescription = + allOperations + . description + %~ Just + . ( <> + "\nOAuth scope: `" + <> ( decodeUtf8With lenientDecode . toStrict . toByteString $ + OAuth.toOAuthScope @scope + ) + <> "`" + ) + . fold instance (HasServer api ctx) => HasServer (DescriptionOAuthScope scope :> api) ctx where type ServerT (DescriptionOAuthScope scope :> api) m = ServerT api m diff --git a/libs/wire-api/src/Wire/API/Routes/Version/Wai.hs b/libs/wire-api/src/Wire/API/Routes/Version/Wai.hs index 939b91c5b75..cd797101f11 100644 --- a/libs/wire-api/src/Wire/API/Routes/Version/Wai.hs +++ b/libs/wire-api/src/Wire/API/Routes/Version/Wai.hs @@ -21,6 +21,7 @@ import Control.Monad.Except (throwError) import Data.ByteString.Conversion import Data.EitherR (fmapL) import Data.Text qualified as T +import Data.Text.Lazy (fromStrict) import Imports import Network.HTTP.Types qualified as HTTP import Network.Wai @@ -44,7 +45,7 @@ versionMiddleware disabledAPIVersions app req k = case parseVersion (removeVersi err :: Text -> IO ResponseReceived err v = k . errorRs' . mkError HTTP.status404 "unsupported-version" $ - "Version " <> cs v <> " is not supported" + "Version " <> fromStrict v <> " is not supported" errint :: IO ResponseReceived errint = diff --git a/libs/wire-api/src/Wire/API/Team/Export.hs b/libs/wire-api/src/Wire/API/Team/Export.hs index f5bfbbe08bb..1f1d4b1462a 100644 --- a/libs/wire-api/src/Wire/API/Team/Export.hs +++ b/libs/wire-api/src/Wire/API/Team/Export.hs @@ -67,7 +67,7 @@ instance ToNamedRecord TeamExportUser where ("managed_by", secureCsvFieldToByteString (tExportManagedBy row)), ("saml_name_id", secureCsvFieldToByteString (tExportSAMLNamedId row)), ("scim_external_id", secureCsvFieldToByteString (tExportSCIMExternalId row)), - ("scim_rich_info", maybe "" (cs . Aeson.encode) (tExportSCIMRichInfo row)), + ("scim_rich_info", maybe "" (C.toStrict . Aeson.encode) (tExportSCIMRichInfo row)), ("user_id", secureCsvFieldToByteString (tExportUserId row)), ("num_devices", secureCsvFieldToByteString (tExportNumDevices row)) ] @@ -100,7 +100,7 @@ allowEmpty p str = Just <$> p str parseByteString :: forall a. FromByteString a => ByteString -> Parser a parseByteString bstr = - case parseOnly (parser @a) (cs (unquoted bstr)) of + case parseOnly (parser @a) (C.fromStrict (unquoted bstr)) of Left err -> fail err Right thing -> pure thing @@ -117,7 +117,13 @@ instance FromNamedRecord TeamExportUser where <*> (nrec .: "managed_by" >>= parseByteString) <*> (nrec .: "saml_name_id" >>= parseByteString) <*> (nrec .: "scim_external_id" >>= parseByteString) - <*> (nrec .: "scim_rich_info" >>= allowEmpty (maybe (fail "failed to decode RichInfo") pure . Aeson.decode . cs)) + <*> ( nrec .: "scim_rich_info" + >>= allowEmpty + ( maybe (fail "failed to decode RichInfo") pure + . Aeson.decode + . C.fromStrict + ) + ) <*> (nrec .: "user_id" >>= parseByteString) <*> (nrec .: "num_devices" >>= parseByteString) diff --git a/libs/wire-api/src/Wire/API/Team/Feature.hs b/libs/wire-api/src/Wire/API/Team/Feature.hs index 8dd48682f7a..55319e388d4 100644 --- a/libs/wire-api/src/Wire/API/Team/Feature.hs +++ b/libs/wire-api/src/Wire/API/Team/Feature.hs @@ -94,6 +94,7 @@ import Control.Lens (makeLenses, (?~)) import Data.Aeson qualified as A import Data.Aeson.Types qualified as A import Data.Attoparsec.ByteString qualified as Parser +import Data.ByteString (fromStrict) import Data.ByteString.Conversion import Data.ByteString.UTF8 qualified as UTF8 import Data.Domain (Domain) @@ -108,6 +109,7 @@ import Data.Schema import Data.Scientific (toBoundedInteger) import Data.Text qualified as T import Data.Text.Encoding qualified as T +import Data.Text.Encoding.Error import Data.Text.Lazy qualified as TL import Data.Time import Deriving.Aeson @@ -509,7 +511,7 @@ data LockStatus = LockStatusLocked | LockStatusUnlocked deriving (ToJSON, FromJSON, S.ToSchema) via (Schema LockStatus) instance FromHttpApiData LockStatus where - parseUrlPiece = maybeToEither "Invalid lock status" . fromByteString . cs + parseUrlPiece = maybeToEither "Invalid lock status" . fromByteString . T.encodeUtf8 instance ToSchema LockStatus where schema = @@ -1106,7 +1108,7 @@ instance RenderableSymbol EnforceFileDownloadLocationConfig where renderSymbol = "EnforceFileDownloadLocationConfig" instance Arbitrary EnforceFileDownloadLocationConfig where - arbitrary = EnforceFileDownloadLocationConfig . fmap (cs . getPrintableString) <$> arbitrary + arbitrary = EnforceFileDownloadLocationConfig . fmap (T.pack . getPrintableString) <$> arbitrary instance ToSchema EnforceFileDownloadLocationConfig where schema = @@ -1164,10 +1166,14 @@ instance S.ToParamSchema FeatureStatus where } instance FromHttpApiData FeatureStatus where - parseUrlPiece = maybe (Left "must be 'enabled' or 'disabled'") Right . fromByteString' . cs + parseUrlPiece = + maybe (Left "must be 'enabled' or 'disabled'") Right + . fromByteString' + . fromStrict + . T.encodeUtf8 instance ToHttpApiData FeatureStatus where - toUrlPiece = cs . toByteString' + toUrlPiece = T.decodeUtf8With lenientDecode . toByteString' instance ToSchema FeatureStatus where schema = diff --git a/libs/wire-api/src/Wire/API/User.hs b/libs/wire-api/src/Wire/API/User.hs index 39e01c892ce..e51b6949746 100644 --- a/libs/wire-api/src/Wire/API/User.hs +++ b/libs/wire-api/src/Wire/API/User.hs @@ -170,6 +170,7 @@ import Data.Attoparsec.ByteString qualified as Parser import Data.Attoparsec.Text qualified as TParser import Data.Bifunctor qualified as Bifunctor import Data.Bits +import Data.ByteString (toStrict) import Data.ByteString.Builder (toLazyByteString) import Data.ByteString.Conversion import Data.CaseInsensitive qualified as CI @@ -194,6 +195,7 @@ import Data.Set qualified as Set import Data.Text qualified as T import Data.Text.Ascii import Data.Text.Encoding qualified as T +import Data.Text.Encoding.Error import Data.Time.Clock (NominalDiffTime) import Data.UUID (UUID, nil) import Data.UUID qualified as UUID @@ -329,7 +331,7 @@ newtype PhonePrefix = PhonePrefix {fromPhonePrefix :: Text} instance Arbitrary PhonePrefix where arbitrary = do digits <- take 8 <$> QC.listOf1 (QC.elements ['0' .. '9']) - pure . PhonePrefix . cs $ "+" <> digits + pure . PhonePrefix . T.pack $ "+" <> digits instance ToSchema PhonePrefix where schema = fromPhonePrefix .= parsedText "PhonePrefix" phonePrefixParser @@ -344,7 +346,7 @@ instance ToByteString PhonePrefix where builder = builder . fromPhonePrefix instance FromHttpApiData PhonePrefix where - parseUrlPiece = Bifunctor.first cs . phonePrefixParser + parseUrlPiece = Bifunctor.first T.pack . phonePrefixParser deriving instance C.Cql PhonePrefix @@ -766,7 +768,11 @@ scimExternalId ManagedByWire (UserSSOId _) = Nothing ssoIssuerAndNameId :: UserSSOId -> Maybe (Text, Text) ssoIssuerAndNameId (UserSSOId (SAML.UserRef (SAML.Issuer uri) nameIdXML)) = Just (fromUri uri, fromNameId nameIdXML) where - fromUri = cs . toLazyByteString . serializeURIRef + fromUri = + T.decodeUtf8With lenientDecode + . toStrict + . toLazyByteString + . serializeURIRef fromNameId = CI.original . SAML.unsafeShowNameID ssoIssuerAndNameId (UserScimExternalId _) = Nothing @@ -1360,10 +1366,14 @@ instance S.ToParamSchema InvitationCode where toParamSchema _ = S.toParamSchema (Proxy @Text) instance FromHttpApiData InvitationCode where - parseQueryParam = bimap cs InvitationCode . validateBase64Url + parseQueryParam = bimap T.pack InvitationCode . validateBase64Url instance ToHttpApiData InvitationCode where - toQueryParam = cs . toByteString . fromInvitationCode + toQueryParam = + T.decodeUtf8With lenientDecode + . toStrict + . toByteString + . fromInvitationCode deriving instance C.Cql InvitationCode @@ -1996,10 +2006,13 @@ instance S.ToParamSchema VerificationAction where } instance FromHttpApiData VerificationAction where - parseUrlPiece = maybeToEither "Invalid verification action" . fromByteString . cs + parseUrlPiece = + maybeToEither "Invalid verification action" + . fromByteString + . T.encodeUtf8 instance ToHttpApiData VerificationAction where - toQueryParam a = cs (toByteString' a) + toQueryParam a = T.decodeUtf8With lenientDecode (toByteString' a) data SendVerificationCode = SendVerificationCode { svcAction :: VerificationAction, diff --git a/libs/wire-api/src/Wire/API/User/Client/DPoPAccessToken.hs b/libs/wire-api/src/Wire/API/User/Client/DPoPAccessToken.hs index 99ed6e13d92..980e376e7fd 100644 --- a/libs/wire-api/src/Wire/API/User/Client/DPoPAccessToken.hs +++ b/libs/wire-api/src/Wire/API/User/Client/DPoPAccessToken.hs @@ -21,13 +21,15 @@ module Wire.API.User.Client.DPoPAccessToken where import Data.Aeson (FromJSON, ToJSON) +import Data.ByteString (fromStrict) import Data.ByteString.Conversion (FromByteString (..), ToByteString (..), fromByteString', toByteString') import Data.OpenApi qualified as S import Data.OpenApi.ParamSchema (ToParamSchema (..)) import Data.SOP import Data.Schema import Data.Text as T -import Data.Text.Encoding (decodeUtf8, encodeUtf8) +import Data.Text.Encoding +import Data.Text.Encoding.Error import Imports import Servant (FromHttpApiData (..), ToHttpApiData (..)) @@ -36,10 +38,14 @@ newtype Proof = Proof {unProof :: ByteString} deriving newtype (FromByteString, ToByteString) instance ToHttpApiData Proof where - toQueryParam = cs . toByteString' + toQueryParam = decodeUtf8With lenientDecode . toByteString' instance FromHttpApiData Proof where - parseQueryParam = maybe (Left "Invalid Proof") Right . fromByteString' . cs + parseQueryParam = + maybe (Left "Invalid Proof") Right + . fromByteString' + . fromStrict + . encodeUtf8 instance ToParamSchema Proof where toParamSchema _ = toParamSchema (Proxy @Text) @@ -56,10 +62,14 @@ instance ToParamSchema DPoPAccessToken where toParamSchema _ = toParamSchema (Proxy @Text) instance ToHttpApiData DPoPAccessToken where - toQueryParam = cs . toByteString' + toQueryParam = decodeUtf8With lenientDecode . toByteString' instance FromHttpApiData DPoPAccessToken where - parseQueryParam = maybe (Left "Invalid DPoPAccessToken") Right . fromByteString' . cs + parseQueryParam = + maybe (Left "Invalid DPoPAccessToken") Right + . fromByteString' + . fromStrict + . encodeUtf8 data AccessTokenType = DPoP deriving (Eq, Show, Generic) diff --git a/libs/wire-api/src/Wire/API/User/Identity.hs b/libs/wire-api/src/Wire/API/User/Identity.hs index 0475554bfeb..88435e20602 100644 --- a/libs/wire-api/src/Wire/API/User/Identity.hs +++ b/libs/wire-api/src/Wire/API/User/Identity.hs @@ -60,13 +60,17 @@ import Data.Aeson qualified as A import Data.Aeson.Types qualified as A import Data.Attoparsec.Text import Data.Bifunctor (first) +import Data.ByteString (fromStrict, toStrict) import Data.ByteString.Conversion +import Data.ByteString.UTF8 qualified as UTF8 import Data.CaseInsensitive qualified as CI import Data.OpenApi (ToParamSchema (..)) import Data.OpenApi qualified as S import Data.Schema import Data.Text qualified as Text -import Data.Text.Encoding (decodeUtf8', encodeUtf8) +import Data.Text.Encoding +import Data.Text.Encoding.Error +import Data.Text.Lazy qualified as LT import Data.Time.Clock import Data.Tuple.Extra (fst3, snd3, thd3) import Imports @@ -189,10 +193,10 @@ instance FromByteString Email where parser = parser >>= maybe (fail "Invalid email") pure . parseEmail instance S.FromHttpApiData Email where - parseUrlPiece = maybe (Left "Invalid email") Right . fromByteString . cs + parseUrlPiece = maybe (Left "Invalid email") Right . fromByteString . encodeUtf8 instance S.ToHttpApiData Email where - toUrlPiece = cs . toByteString' + toUrlPiece = decodeUtf8With lenientDecode . toByteString' instance Arbitrary Email where arbitrary = do @@ -281,10 +285,10 @@ instance FromByteString Phone where parser = parser >>= maybe (fail "Invalid phone") pure . parsePhone instance S.FromHttpApiData Phone where - parseUrlPiece = maybe (Left "Invalid phone") Right . fromByteString . cs + parseUrlPiece = maybe (Left "Invalid phone") Right . fromByteString . encodeUtf8 instance S.ToHttpApiData Phone where - toUrlPiece = cs . toByteString' + toUrlPiece = decodeUtf8With lenientDecode . toByteString' instance Arbitrary Phone where arbitrary = @@ -331,12 +335,12 @@ data UserSSOId instance C.Cql UserSSOId where ctype = C.Tagged C.TextColumn - fromCql (C.CqlText t) = case A.eitherDecode $ cs t of + fromCql (C.CqlText t) = case A.eitherDecode $ fromStrict (encodeUtf8 t) of Right i -> pure i Left msg -> Left $ "fromCql: Invalid UserSSOId: " ++ msg fromCql _ = Left "fromCql: UserSSOId: CqlText expected" - toCql = C.toCql . cs @LByteString @Text . A.encode + toCql = C.toCql . decodeUtf8With lenientDecode . toStrict . A.encode -- | FUTUREWORK: This schema should ideally be a choice of either tenant+subject, or scim_external_id -- but this is currently not possible to derive in swagger2 @@ -394,7 +398,7 @@ lenientlyParseSAMLIssuer mbtxt = forM mbtxt $ \txt -> do asurl :: Either String SAML.Issuer asurl = bimap show SAML.Issuer $ - URI.parseURI URI.laxURIParserOptions (cs txt) + URI.parseURI URI.laxURIParserOptions (encodeUtf8 . LT.toStrict $ txt) err :: String err = "lenientlyParseSAMLIssuer: " <> show (asxml, asurl, mbtxt) @@ -412,11 +416,11 @@ lenientlyParseSAMLNameID (Just txt) = do maybe (Left "not an email") (fmap emailToSAMLNameID . validateEmail) - (parseEmail (cs txt)) + (parseEmail . LT.toStrict $ txt) astxt :: Either String SAML.NameID astxt = do - nm <- mkName (cs txt) + nm <- mkName . LT.toStrict $ txt SAML.mkNameID (SAML.mkUNameIDUnspecified (fromName nm)) Nothing Nothing Nothing err :: String @@ -449,7 +453,12 @@ mkSampleUref :: Text -> Text -> SAML.UserRef mkSampleUref iseed nseed = SAML.UserRef issuer nameid where issuer :: SAML.Issuer - issuer = SAML.Issuer ([uri|http://example.com/|] & URI.pathL .~ cs ("/" cs iseed)) + issuer = + SAML.Issuer + ( [uri|http://example.com/|] + & URI.pathL + .~ UTF8.fromString ("/" Text.unpack iseed) + ) nameid :: SAML.NameID nameid = fromRight (error "impossible") $ do diff --git a/libs/wire-api/src/Wire/API/User/IdentityProvider.hs b/libs/wire-api/src/Wire/API/User/IdentityProvider.hs index e954f15c2e6..544e8718685 100644 --- a/libs/wire-api/src/Wire/API/User/IdentityProvider.hs +++ b/libs/wire-api/src/Wire/API/User/IdentityProvider.hs @@ -28,11 +28,15 @@ import Data.Aeson.Types (parseMaybe) import Data.Attoparsec.ByteString qualified as AP import Data.Binary.Builder qualified as BSB import Data.ByteString.Conversion qualified as BSC +import Data.ByteString.Lazy (fromStrict, toStrict) import Data.HashMap.Strict.InsOrd (InsOrdHashMap) import Data.HashMap.Strict.InsOrd qualified as InsOrdHashMap import Data.Id (TeamId) import Data.OpenApi import Data.Proxy (Proxy (Proxy)) +import Data.Text.Encoding +import Data.Text.Encoding.Error +import Data.Text.Lazy qualified as LT import Imports import Network.HTTP.Media ((//)) import SAML2.WebSSO (IdPConfig) @@ -98,12 +102,14 @@ instance BSC.FromByteString WireIdPAPIVersion where <|> (AP.string "v2" >> pure WireIdPAPIV2) instance FromHttpApiData WireIdPAPIVersion where - parseQueryParam txt = maybe err Right $ BSC.fromByteString' (cs txt) + parseQueryParam txt = + maybe err Right $ + (BSC.fromByteString' . fromStrict . encodeUtf8) txt where err = Left $ "FromHttpApiData WireIdPAPIVersion: " <> txt instance ToHttpApiData WireIdPAPIVersion where - toQueryParam = cs . BSC.toByteString' + toQueryParam = decodeUtf8With lenientDecode . BSC.toByteString' instance ToParamSchema WireIdPAPIVersion where toParamSchema Proxy = @@ -153,10 +159,13 @@ instance Accept RawXML where contentType Proxy = "application" // "xml" instance MimeUnrender RawXML IdPMetadataInfo where - mimeUnrender Proxy raw = IdPMetadataValue (cs raw) <$> mimeUnrender (Proxy @SAML.XML) raw + mimeUnrender Proxy raw = + IdPMetadataValue + (decodeUtf8With lenientDecode . toStrict $ raw) + <$> mimeUnrender (Proxy @SAML.XML) raw instance MimeRender RawXML RawIdPMetadata where - mimeRender Proxy (RawIdPMetadata raw) = cs raw + mimeRender Proxy (RawIdPMetadata raw) = fromStrict . encodeUtf8 $ raw newtype RawIdPMetadata = RawIdPMetadata Text deriving (Eq, Show, Generic) @@ -164,7 +173,7 @@ newtype RawIdPMetadata = RawIdPMetadata Text instance FromJSON IdPMetadataInfo where parseJSON = withObject "IdPMetadataInfo" $ \obj -> do raw <- obj .: "value" - either fail (pure . IdPMetadataValue raw) (SAML.decode (cs raw)) + either fail (pure . IdPMetadataValue raw) (SAML.decode (LT.fromStrict raw)) instance ToJSON IdPMetadataInfo where toJSON (IdPMetadataValue _ x) = diff --git a/libs/wire-api/src/Wire/API/User/RichInfo.hs b/libs/wire-api/src/Wire/API/User/RichInfo.hs index e6723b9d651..d84ba4f3c2f 100644 --- a/libs/wire-api/src/Wire/API/User/RichInfo.hs +++ b/libs/wire-api/src/Wire/API/User/RichInfo.hs @@ -133,7 +133,7 @@ ciObject name sch = mkSchema s r w desc = S.description ?~ ("json object with case-insensitive fields." :: Text) r :: A.Value -> A.Parser b - r = A.withObject (cs name) f + r = A.withObject (Text.unpack name) f where f :: A.Object -> A.Parser b f = schemaIn sch . g @@ -350,8 +350,8 @@ instance ToSchema RichField where instance Arbitrary RichField where arbitrary = RichField - <$> (CI.mk . cs . QC.getPrintableString <$> arbitrary) - <*> (cs . QC.getPrintableString <$> arbitrary) + <$> (CI.mk . Text.pack . QC.getPrintableString <$> arbitrary) + <*> (Text.pack . QC.getPrintableString <$> arbitrary) shrink (RichField k v) = RichField <$> QC.shrink k <*> QC.shrink v -------------------------------------------------------------------------------- diff --git a/libs/wire-api/src/Wire/API/User/Saml.hs b/libs/wire-api/src/Wire/API/User/Saml.hs index 09ad0d24367..f165a17f76c 100644 --- a/libs/wire-api/src/Wire/API/User/Saml.hs +++ b/libs/wire-api/src/Wire/API/User/Saml.hs @@ -28,11 +28,14 @@ import Control.Lens (makeLenses) import Control.Monad.Except import Data.Aeson hiding (fieldLabelModifier) import Data.Aeson.TH hiding (fieldLabelModifier) +import Data.ByteString (toStrict) import Data.ByteString.Builder qualified as Builder import Data.Id (UserId) import Data.OpenApi import Data.Proxy (Proxy (Proxy)) import Data.Text qualified as T +import Data.Text.Encoding +import Data.Text.Encoding.Error import Data.Time import GHC.TypeLits (KnownSymbol, symbolVal) import GHC.Types (Symbol) @@ -66,8 +69,15 @@ deriveJSON deriveJSONOptions ''VerdictFormat mkVerdictGrantedFormatMobile :: MonadError String m => URI -> SetCookie -> UserId -> m URI mkVerdictGrantedFormatMobile before cky uid = parseURI' - . substituteVar "cookie" (cs . Builder.toLazyByteString . renderSetCookie $ cky) - . substituteVar "userid" (cs . show $ uid) + . substituteVar + "cookie" + ( decodeUtf8With lenientDecode + . toStrict + . Builder.toLazyByteString + . renderSetCookie + $ cky + ) + . substituteVar "userid" (T.pack . show $ uid) $ renderURI before mkVerdictDeniedFormatMobile :: MonadError String m => URI -> Text -> m URI diff --git a/libs/wire-api/src/Wire/API/User/Scim.hs b/libs/wire-api/src/Wire/API/User/Scim.hs index 1b3e4e50b5e..d8482447523 100644 --- a/libs/wire-api/src/Wire/API/User/Scim.hs +++ b/libs/wire-api/src/Wire/API/User/Scim.hs @@ -61,6 +61,7 @@ import Data.Map qualified as Map import Data.Misc (PlainTextPassword6) import Data.OpenApi hiding (Operation) import Data.Proxy +import Data.Text qualified as T import Data.Text.Encoding (decodeUtf8, encodeUtf8) import Data.Time.Clock (UTCTime) import Imports @@ -252,8 +253,8 @@ instance QC.Arbitrary (Scim.User SparTag) where where addFields :: Scim.User.User tag -> QC.Gen (Scim.User.User tag) addFields usr = do - gexternalId <- cs . QC.getPrintableString <$$> QC.arbitrary - gdisplayName <- cs . QC.getPrintableString <$$> QC.arbitrary + gexternalId <- T.pack . QC.getPrintableString <$$> QC.arbitrary + gdisplayName <- T.pack . QC.getPrintableString <$$> QC.arbitrary gactive <- Just . Scim.ScimBool <$> QC.arbitrary -- (`Nothing` maps on `Just True` and was in the way of a unit test.) gemails <- catMaybes <$> (A.decode <$$> QC.listOf (QC.elements ["a@b.c", "x@y,z", "roland@st.uv"])) pure @@ -268,7 +269,7 @@ instance QC.Arbitrary (Scim.User SparTag) where genSchemas = QC.listOf1 $ QC.elements Scim.fakeEnumSchema genUserName :: QC.Gen Text - genUserName = cs . QC.getPrintableString <$> QC.arbitrary + genUserName = T.pack . QC.getPrintableString <$> QC.arbitrary genExtra :: QC.Gen ScimUserExtra genExtra = QC.arbitrary diff --git a/libs/wire-api/src/Wire/API/User/Search.hs b/libs/wire-api/src/Wire/API/User/Search.hs index 8b2fa6fb710..435c7cf3998 100644 --- a/libs/wire-api/src/Wire/API/User/Search.hs +++ b/libs/wire-api/src/Wire/API/User/Search.hs @@ -73,7 +73,7 @@ instance ToParamSchema PagingState where toParamSchema _ = toParamSchema (Proxy @Text) instance FromHttpApiData PagingState where - parseQueryParam s = mapLeft cs $ PagingState <$> validateBase64Url s + parseQueryParam s = mapLeft T.pack $ PagingState <$> validateBase64Url s instance ToHttpApiData PagingState where toQueryParam = toText . unPagingState diff --git a/libs/wire-api/test/golden/Test/Wire/API/Golden/Runner.hs b/libs/wire-api/test/golden/Test/Wire/API/Golden/Runner.hs index f4c9a736005..6a458413d84 100644 --- a/libs/wire-api/test/golden/Test/Wire/API/Golden/Runner.hs +++ b/libs/wire-api/test/golden/Test/Wire/API/Golden/Runner.hs @@ -33,6 +33,7 @@ import Data.ByteString.Lazy qualified as LBS import Data.ProtoLens.Encoding (decodeMessage, encodeMessage) import Data.ProtoLens.Message (Message) import Data.ProtoLens.TextFormat (readMessage, showMessage) +import Data.String.Conversions import Data.Text.Lazy.IO qualified as LText import Imports import Test.Tasty (TestTree) diff --git a/libs/wire-api/test/unit/Test/Wire/API/Routes/Version.hs b/libs/wire-api/test/unit/Test/Wire/API/Routes/Version.hs index 603e14776af..b6224933398 100644 --- a/libs/wire-api/test/unit/Test/Wire/API/Routes/Version.hs +++ b/libs/wire-api/test/unit/Test/Wire/API/Routes/Version.hs @@ -4,6 +4,7 @@ import Data.Aeson as Aeson import Data.Binary.Builder import Data.ByteString.Conversion import Data.Set as Set +import Data.String.Conversions import Imports import Servant.API import Test.Tasty diff --git a/libs/wire-api/test/unit/Test/Wire/API/Routes/Version/Wai.hs b/libs/wire-api/test/unit/Test/Wire/API/Routes/Version/Wai.hs index 573904b8600..2e87537f60b 100644 --- a/libs/wire-api/test/unit/Test/Wire/API/Routes/Version/Wai.hs +++ b/libs/wire-api/test/unit/Test/Wire/API/Routes/Version/Wai.hs @@ -2,6 +2,7 @@ module Test.Wire.API.Routes.Version.Wai where import Data.Proxy import Data.Set qualified as Set +import Data.String.Conversions import Data.Text as T import Imports import Network.HTTP.Types.Status (status200, status400) diff --git a/libs/wire-api/test/unit/Test/Wire/API/User/Search.hs b/libs/wire-api/test/unit/Test/Wire/API/User/Search.hs index ad437d6d06f..a1fd13f4252 100644 --- a/libs/wire-api/test/unit/Test/Wire/API/User/Search.hs +++ b/libs/wire-api/test/unit/Test/Wire/API/User/Search.hs @@ -20,6 +20,7 @@ module Test.Wire.API.User.Search where import Data.Aeson (encode, toJSON) import Data.Aeson qualified as Aeson import Data.Aeson.KeyMap qualified as KeyMap +import Data.String.Conversions import Imports import Test.Tasty qualified as T import Test.Tasty.QuickCheck (counterexample, testProperty) diff --git a/libs/wire-api/wire-api.cabal b/libs/wire-api/wire-api.cabal index a5ad166cf26..e17d212cde5 100644 --- a/libs/wire-api/wire-api.cabal +++ b/libs/wire-api/wire-api.cabal @@ -614,6 +614,7 @@ test-suite wire-api-golden-tests , lens , pem , proto-lens + , string-conversions , tasty , tasty-hunit , text @@ -689,6 +690,7 @@ test-suite wire-api-tests , schema-profunctor , servant , servant-server + , string-conversions , tasty , tasty-hspec , tasty-hunit diff --git a/libs/wire-subsystems/default.nix b/libs/wire-subsystems/default.nix index bd3ef35a59c..dc35149eb50 100644 --- a/libs/wire-subsystems/default.nix +++ b/libs/wire-subsystems/default.nix @@ -26,6 +26,7 @@ , QuickCheck , quickcheck-instances , retry +, string-conversions , text , tinylog , types-common @@ -73,6 +74,7 @@ mkDerivation { polysemy-wire-zoo QuickCheck quickcheck-instances + string-conversions types-common wire-api ]; diff --git a/libs/wire-subsystems/test/unit/Wire/NotificationSubsystem/InterpreterSpec.hs b/libs/wire-subsystems/test/unit/Wire/NotificationSubsystem/InterpreterSpec.hs index 4677a0d1bfd..1b5aee83b2b 100644 --- a/libs/wire-subsystems/test/unit/Wire/NotificationSubsystem/InterpreterSpec.hs +++ b/libs/wire-subsystems/test/unit/Wire/NotificationSubsystem/InterpreterSpec.hs @@ -8,6 +8,7 @@ import Data.List.NonEmpty (NonEmpty ((:|)), fromList) import Data.List1 qualified as List1 import Data.Range (fromRange, toRange) import Data.Set qualified as Set +import Data.String.Conversions import Data.Time.Clock.DiffTime import Gundeck.Types.Push.V2 qualified as V2 import Imports diff --git a/libs/wire-subsystems/wire-subsystems.cabal b/libs/wire-subsystems/wire-subsystems.cabal index a631c0e2737..1c7676e7140 100644 --- a/libs/wire-subsystems/wire-subsystems.cabal +++ b/libs/wire-subsystems/wire-subsystems.cabal @@ -127,6 +127,7 @@ test-suite wire-subsystems-tests , polysemy-wire-zoo , QuickCheck , quickcheck-instances + , string-conversions , types-common , wire-api , wire-subsystems diff --git a/services/background-worker/background-worker.cabal b/services/background-worker/background-worker.cabal index 36e566299da..31657b00ca5 100644 --- a/services/background-worker/background-worker.cabal +++ b/services/background-worker/background-worker.cabal @@ -49,6 +49,7 @@ library , transformers-base , types-common , unliftio + , utf8-string , wai-utilities , wire-api , wire-api-federation diff --git a/services/background-worker/default.nix b/services/background-worker/default.nix index 31ce1fae0eb..3698011087d 100644 --- a/services/background-worker/default.nix +++ b/services/background-worker/default.nix @@ -37,6 +37,7 @@ , transformers-base , types-common , unliftio +, utf8-string , wai , wai-utilities , wire-api @@ -71,6 +72,7 @@ mkDerivation { transformers-base types-common unliftio + utf8-string wai-utilities wire-api wire-api-federation diff --git a/services/background-worker/src/Wire/BackgroundWorker.hs b/services/background-worker/src/Wire/BackgroundWorker.hs index 31a9c769034..b5e745d6558 100644 --- a/services/background-worker/src/Wire/BackgroundWorker.hs +++ b/services/background-worker/src/Wire/BackgroundWorker.hs @@ -5,6 +5,7 @@ module Wire.BackgroundWorker where import Data.Domain import Data.Map.Strict qualified as Map import Data.Metrics.Servant qualified as Metrics +import Data.Text qualified as T import Imports import Network.AMQP qualified as Q import Network.Wai.Utilities.Server @@ -47,7 +48,7 @@ run opts = do -- Close the channel. `extended` will then close the connection, flushing messages to the server. Log.info l $ Log.msg $ Log.val "Closing RabbitMQ channel" Q.closeChannel chan - let server = defaultServer (cs $ opts.backgroundWorker._host) opts.backgroundWorker._port env.logger env.metrics + let server = defaultServer (T.unpack $ opts.backgroundWorker._host) opts.backgroundWorker._port env.logger env.metrics settings <- newSettings server -- Additional cleanup when shutting down via signals. runSettingsWithCleanup cleanup settings (servantApp env) Nothing diff --git a/services/background-worker/src/Wire/BackgroundWorker/Health.hs b/services/background-worker/src/Wire/BackgroundWorker/Health.hs index dc0cc0a97d7..f56c0404c4d 100644 --- a/services/background-worker/src/Wire/BackgroundWorker/Health.hs +++ b/services/background-worker/src/Wire/BackgroundWorker/Health.hs @@ -1,5 +1,6 @@ module Wire.BackgroundWorker.Health where +import Data.ByteString.Lazy.UTF8 qualified as UTF8 import Data.Map.Strict qualified as Map import Imports import Servant @@ -17,7 +18,7 @@ statusWorkersImpl = do notWorkingWorkers <- Map.keys . Map.filter not <$> (readIORef =<< asks statuses) if null notWorkingWorkers then pure NoContent - else lift $ throwError err500 {errBody = "These workers are not working: " <> cs (show notWorkingWorkers)} + else lift $ throwError err500 {errBody = "These workers are not working: " <> UTF8.fromString (show notWorkingWorkers)} api :: Env -> HealthAPI AsServer api env = fromServant $ hoistServer (Proxy @(ToServant HealthAPI AsApi)) (runAppT env) (toServant apiInAppT) diff --git a/services/brig/brig.cabal b/services/brig/brig.cabal index a57c21f5e6c..9ad17d98040 100644 --- a/services/brig/brig.cabal +++ b/services/brig/brig.cabal @@ -351,6 +351,7 @@ library , unliftio >=0.2 , unordered-containers >=0.2 , uri-bytestring >=0.2 + , utf8-string , uuid >=1.3.5 , vector >=0.11 , wai >=3.0 @@ -496,6 +497,7 @@ executable brig-integration , servant-client-core , spar , streaming-commons + , string-conversions , tasty >=1.0 , tasty-ant-xml , tasty-cannon >=0.3.4 diff --git a/services/brig/default.nix b/services/brig/default.nix index 37c5d355190..fc3eff7812f 100644 --- a/services/brig/default.nix +++ b/services/brig/default.nix @@ -122,6 +122,7 @@ , statistics , stomp-queue , streaming-commons +, string-conversions , tasty , tasty-ant-xml , tasty-cannon @@ -144,6 +145,7 @@ , unliftio , unordered-containers , uri-bytestring +, utf8-string , uuid , vector , wai @@ -277,6 +279,7 @@ mkDerivation { unliftio unordered-containers uri-bytestring + utf8-string uuid vector wai @@ -352,6 +355,7 @@ mkDerivation { servant-client-core spar streaming-commons + string-conversions tasty tasty-ant-xml tasty-cannon diff --git a/services/brig/src/Brig/API/Client.hs b/services/brig/src/Brig/API/Client.hs index 65bb1ab8b77..2fbd3390af5 100644 --- a/services/brig/src/Brig/API/Client.hs +++ b/services/brig/src/Brig/API/Client.hs @@ -76,6 +76,7 @@ import Cassandra (MonadClient) import Control.Error import Control.Lens (view) import Control.Monad.Trans.Except (except) +import Data.ByteString (toStrict) import Data.ByteString.Conversion import Data.Code as Code import Data.Domain @@ -86,6 +87,8 @@ import Data.Map.Strict qualified as Map import Data.Misc (PlainTextPassword6) import Data.Qualified import Data.Set qualified as Set +import Data.Text.Encoding qualified as T +import Data.Text.Encoding.Error import Data.Time.Clock (UTCTime) import Imports import Network.HTTP.Types.Method (StdMethod) @@ -539,8 +542,19 @@ createAccessToken luid cid method link proof = do <$> note NotATeamUser (userTeam =<< mUser) <*> note MissingHandle (userHandle =<< mUser) <*> note MissingName (userDisplayName <$> mUser) - nonce <- ExceptT $ note NonceNotFound <$> wrapClient (Nonce.lookupAndDeleteNonce uid (cs $ toByteString cid)) - httpsUrl <- except $ note MisconfiguredRequestUrl $ fromByteString $ "https://" <> toByteString' domain <> "/" <> cs (toUrlPiece link) + nonce <- + ExceptT $ + note NonceNotFound + <$> wrapClient + ( Nonce.lookupAndDeleteNonce + uid + (T.decodeUtf8With lenientDecode . toStrict $ toByteString cid) + ) + httpsUrl <- + except $ + note MisconfiguredRequestUrl $ + fromByteString $ + "https://" <> toByteString' domain <> "/" <> T.encodeUtf8 (toUrlPiece link) maxSkewSeconds <- Opt.setDpopMaxSkewSecs <$> view settings expiresIn <- Opt.setDpopTokenExpirationTimeSecs <$> view settings now <- fromUTCTime <$> lift (liftSem Now.get) diff --git a/services/brig/src/Brig/API/Error.hs b/services/brig/src/Brig/API/Error.hs index 14cef9c4be8..23a24bad4e2 100644 --- a/services/brig/src/Brig/API/Error.hs +++ b/services/brig/src/Brig/API/Error.hs @@ -25,6 +25,7 @@ import Data.Aeson.KeyMap qualified as KeyMap import Data.ByteString.Conversion import Data.Domain (Domain) import Data.Jwt.Tools (DPoPTokenGenerationError (..)) +import Data.Text.Lazy as LT import Data.ZAuth.Validation qualified as ZAuth import Imports import Network.HTTP.Types.Header @@ -447,7 +448,7 @@ customerExtensionBlockedDomain domain = Wai.mkError (mkStatus 451 "Unavailable F where msg = "[Customer extension] the email domain " - <> cs (show domain) + <> LT.pack (show domain) <> " that you are attempting to register a user with has been \ \blocked for creating wire users. Please contact your IT department." diff --git a/services/brig/src/Brig/API/Internal.hs b/services/brig/src/Brig/API/Internal.hs index 28d004f2ec8..12e529d9886 100644 --- a/services/brig/src/Brig/API/Internal.hs +++ b/services/brig/src/Brig/API/Internal.hs @@ -69,6 +69,8 @@ import Data.Id as Id import Data.Map.Strict qualified as Map import Data.Qualified import Data.Set qualified as Set +import Data.Text qualified as T +import Data.Text.Lazy qualified as LT import Data.Time.Clock (UTCTime) import Data.Time.Clock.System import Imports hiding (head) @@ -296,24 +298,24 @@ addFederationRemote fedDomConf = do "keeping track of remote domains in the brig config file is deprecated, but as long as we \ \do that, adding a domain with different settings than in the config file is not allowed. want " <> ( "Just " - <> cs (show fedDomConf) + <> T.pack (show fedDomConf) <> "or Nothing, " ) <> ( "got " - <> cs (show (Map.lookup (domain fedDomConf) cfg)) + <> T.pack (show (Map.lookup (domain fedDomConf) cfg)) ) updateFederationRemote :: (Member FederationConfigStore r) => Domain -> FederationDomainConfig -> (Handler r) () updateFederationRemote dom fedcfg = do if (dom /= fedcfg.domain) then - throwError . fedError . FederationUnexpectedError . cs $ + throwError . fedError . FederationUnexpectedError . T.pack $ "federation domain of a given peer cannot be changed from " <> show (domain fedcfg) <> " to " <> show dom <> "." else lift (liftSem (E.updateFederationConfig fedcfg)) >>= \case UpdateFederationSuccess -> pure () UpdateFederationRemoteNotFound -> - throwError . fedError . FederationUnexpectedError . cs $ + throwError . fedError . FederationUnexpectedError . T.pack $ "federation domain does not exist and cannot be updated: " <> show (dom, fedcfg) UpdateFederationRemoteDivergingConfig -> throwError . fedError . FederationUnexpectedError $ @@ -571,7 +573,13 @@ listActivatedAccounts elh includePendingInvitations = do getActivationCodeH :: Maybe Email -> Maybe Phone -> (Handler r) GetActivationCodeResp getActivationCodeH (Just email) Nothing = getActivationCode (Left email) getActivationCodeH Nothing (Just phone) = getActivationCode (Right phone) -getActivationCodeH bade badp = throwStd (badRequest ("need exactly one of email, phone: " <> Imports.cs (show (bade, badp)))) +getActivationCodeH bade badp = + throwStd + ( badRequest + ( "need exactly one of email, phone: " + <> LT.pack (show (bade, badp)) + ) + ) getActivationCode :: Either Email Phone -> (Handler r) GetActivationCodeResp getActivationCode emailOrPhone = do @@ -587,7 +595,11 @@ getPasswordResetCodeH :: (Handler r) GetPasswordResetCodeResp getPasswordResetCodeH (Just email) Nothing = getPasswordResetCode (Left email) getPasswordResetCodeH Nothing (Just phone) = getPasswordResetCode (Right phone) -getPasswordResetCodeH bade badp = throwStd (badRequest ("need exactly one of email, phone: " <> Imports.cs (show (bade, badp)))) +getPasswordResetCodeH bade badp = + throwStd + ( badRequest + ("need exactly one of email, phone: " <> LT.pack (show (bade, badp))) + ) getPasswordResetCode :: ( Member CodeStore r, @@ -659,7 +671,11 @@ revokeIdentityH :: (Handler r) NoContent revokeIdentityH (Just email) Nothing = lift $ NoContent <$ API.revokeIdentity (Left email) revokeIdentityH Nothing (Just phone) = lift $ NoContent <$ API.revokeIdentity (Right phone) -revokeIdentityH bade badp = throwStd (badRequest ("need exactly one of email, phone: " <> Imports.cs (show (bade, badp)))) +revokeIdentityH bade badp = + throwStd + ( badRequest + ("need exactly one of email, phone: " <> LT.pack (show (bade, badp))) + ) updateConnectionInternalH :: ( Member GalleyProvider r, @@ -676,7 +692,11 @@ updateConnectionInternalH updateConn = do checkBlacklistH :: Member BlacklistStore r => Maybe Email -> Maybe Phone -> (Handler r) CheckBlacklistResponse checkBlacklistH (Just email) Nothing = checkBlacklist (Left email) checkBlacklistH Nothing (Just phone) = checkBlacklist (Right phone) -checkBlacklistH bade badp = throwStd (badRequest ("need exactly one of email, phone: " <> Imports.cs (show (bade, badp)))) +checkBlacklistH bade badp = + throwStd + ( badRequest + ("need exactly one of email, phone: " <> LT.pack (show (bade, badp))) + ) checkBlacklist :: Member BlacklistStore r => Either Email Phone -> (Handler r) CheckBlacklistResponse checkBlacklist emailOrPhone = lift $ bool NotBlacklisted YesBlacklisted <$> API.isBlacklisted emailOrPhone @@ -684,7 +704,11 @@ checkBlacklist emailOrPhone = lift $ bool NotBlacklisted YesBlacklisted <$> API. deleteFromBlacklistH :: Member BlacklistStore r => Maybe Email -> Maybe Phone -> (Handler r) NoContent deleteFromBlacklistH (Just email) Nothing = deleteFromBlacklist (Left email) deleteFromBlacklistH Nothing (Just phone) = deleteFromBlacklist (Right phone) -deleteFromBlacklistH bade badp = throwStd (badRequest ("need exactly one of email, phone: " <> Imports.cs (show (bade, badp)))) +deleteFromBlacklistH bade badp = + throwStd + ( badRequest + ("need exactly one of email, phone: " <> LT.pack (show (bade, badp))) + ) deleteFromBlacklist :: Member BlacklistStore r => Either Email Phone -> (Handler r) NoContent deleteFromBlacklist emailOrPhone = lift $ NoContent <$ API.blacklistDelete emailOrPhone @@ -692,7 +716,11 @@ deleteFromBlacklist emailOrPhone = lift $ NoContent <$ API.blacklistDelete email addBlacklistH :: Member BlacklistStore r => Maybe Email -> Maybe Phone -> (Handler r) NoContent addBlacklistH (Just email) Nothing = addBlacklist (Left email) addBlacklistH Nothing (Just phone) = addBlacklist (Right phone) -addBlacklistH bade badp = throwStd (badRequest ("need exactly one of email, phone: " <> Imports.cs (show (bade, badp)))) +addBlacklistH bade badp = + throwStd + ( badRequest + ("need exactly one of email, phone: " <> LT.pack (show (bade, badp))) + ) addBlacklist :: Member BlacklistStore r => Either Email Phone -> (Handler r) NoContent addBlacklist emailOrPhone = lift $ NoContent <$ API.blacklistInsert emailOrPhone diff --git a/services/brig/src/Brig/API/MLS/KeyPackages/Validation.hs b/services/brig/src/Brig/API/MLS/KeyPackages/Validation.hs index 0783663e807..16707b15ff4 100644 --- a/services/brig/src/Brig/API/MLS/KeyPackages/Validation.hs +++ b/services/brig/src/Brig/API/MLS/KeyPackages/Validation.hs @@ -34,7 +34,7 @@ import Data.ByteString qualified as LBS import Data.Qualified import Data.Time.Clock import Data.Time.Clock.POSIX -import Imports hiding (cs) +import Imports import Wire.API.Error import Wire.API.Error.Brig import Wire.API.MLS.CipherSuite diff --git a/services/brig/src/Brig/API/OAuth.hs b/services/brig/src/Brig/API/OAuth.hs index 43453f45548..8643e8eff6d 100644 --- a/services/brig/src/Brig/API/OAuth.hs +++ b/services/brig/src/Brig/API/OAuth.hs @@ -39,6 +39,7 @@ import Data.Id import Data.Misc import Data.Set qualified as Set import Data.Text.Ascii +import Data.Text.Encoding qualified as T import Data.Time import Imports hiding (exp) import OpenSSL.Random (randBytes) @@ -125,13 +126,40 @@ createNewOAuthAuthorizationCode :: UserId -> CreateOAuthAuthorizationCodeRequest createNewOAuthAuthorizationCode uid code = do runExceptT (validateAndCreateAuthorizationCode uid code) >>= \case Right oauthCode -> - pure $ CreateOAuthCodeSuccess $ code.redirectUri & addParams [("code", toByteString' oauthCode), ("state", cs code.state)] + pure $ + CreateOAuthCodeSuccess $ + code.redirectUri + & addParams + [ ("code", toByteString' oauthCode), + ("state", T.encodeUtf8 code.state) + ] Left CreateNewOAuthCodeErrorFeatureDisabled -> - pure $ CreateOAuthCodeFeatureDisabled $ code.redirectUri & addParams [("error", "access_denied"), ("error_description", "OAuth is not enabled"), ("state", cs code.state)] + pure $ + CreateOAuthCodeFeatureDisabled $ + code.redirectUri + & addParams + [ ("error", "access_denied"), + ("error_description", "OAuth is not enabled"), + ("state", T.encodeUtf8 code.state) + ] Left CreateNewOAuthCodeErrorClientNotFound -> - pure $ CreateOAuthCodeClientNotFound $ code.redirectUri & addParams [("error", "access_denied"), ("error_description", "The client ID was not found"), ("state", cs code.state)] + pure $ + CreateOAuthCodeClientNotFound $ + code.redirectUri + & addParams + [ ("error", "access_denied"), + ("error_description", "The client ID was not found"), + ("state", T.encodeUtf8 code.state) + ] Left CreateNewOAuthCodeErrorUnsupportedResponseType -> - pure $ CreateOAuthCodeUnsupportedResponseType $ code.redirectUri & addParams [("error", "access_denied"), ("error_description", "The client ID was not found"), ("state", cs code.state)] + pure $ + CreateOAuthCodeUnsupportedResponseType $ + code.redirectUri + & addParams + [ ("error", "access_denied"), + ("error_description", "The client ID was not found"), + ("state", T.encodeUtf8 code.state) + ] Left CreateNewOAuthCodeErrorRedirectUrlMissMatch -> pure CreateOAuthCodeRedirectUrlMissMatch diff --git a/services/brig/src/Brig/API/Public.hs b/services/brig/src/Brig/API/Public.hs index c72ee3d2db8..f4d77b27a52 100644 --- a/services/brig/src/Brig/API/Public.hs +++ b/services/brig/src/Brig/API/Public.hs @@ -78,8 +78,10 @@ import Control.Monad.Catch (throwM) import Control.Monad.Except import Data.Aeson hiding (json) import Data.Bifunctor +import Data.ByteString (fromStrict, toStrict) import Data.ByteString.Lazy qualified as Lazy import Data.ByteString.Lazy.Char8 qualified as LBS +import Data.ByteString.UTF8 qualified as UTF8 import Data.CommaSeparatedList import Data.Domain import Data.FileEmbed @@ -95,6 +97,7 @@ import Data.Range import Data.Schema () import Data.Text qualified as Text import Data.Text.Ascii qualified as Ascii +import Data.Text.Encoding qualified as Text import Data.Text.Lazy (pack) import Data.Time.Clock (UTCTime) import Data.ZAuth.Token qualified as ZAuth @@ -217,7 +220,7 @@ versionedSwaggerDocsAPI Nothing = allroutes (throwError listAllVersionsResp) Servant.Server (SwaggerSchemaUI "swagger-ui" "swagger.json") allroutes action = -- why? see 'SwaggerSchemaUI' type. - action :<|> action :<|> action :<|> error (cs listAllVersionsHTML) + action :<|> action :<|> action :<|> error (UTF8.toString . toStrict $ listAllVersionsHTML) listAllVersionsResp :: ServerError listAllVersionsResp = ServerError 200 mempty listAllVersionsHTML [("Content-Type", "text/html;charset=utf-8")] @@ -227,7 +230,11 @@ versionedSwaggerDocsAPI Nothing = allroutes (throwError listAllVersionsResp) "

please pick an api version

" <> mconcat [ let url = "/" <> toQueryParam v <> "/api/swagger-ui/" - in " cs url <> "\">" <> cs url <> "
" + in " (fromStrict . Text.encodeUtf8 $ url) + <> "\">" + <> (fromStrict . Text.encodeUtf8 $ url) + <> "
" | v <- [minBound :: Version ..] ] <> "" diff --git a/services/brig/src/Brig/API/User.hs b/services/brig/src/Brig/API/User.hs index 6db13202f28..05e4a2b43aa 100644 --- a/services/brig/src/Brig/API/User.hs +++ b/services/brig/src/Brig/API/User.hs @@ -157,7 +157,7 @@ import Data.Misc import Data.Qualified import Data.Time.Clock (UTCTime, addUTCTime, diffUTCTime) import Data.UUID.V4 (nextRandom) -import Imports hiding (cs) +import Imports import Network.Wai.Utilities import Polysemy import Polysemy.Input (Input) diff --git a/services/brig/src/Brig/API/Util.hs b/services/brig/src/Brig/API/Util.hs index 67693d37300..54f04975a51 100644 --- a/services/brig/src/Brig/API/Util.hs +++ b/services/brig/src/Brig/API/Util.hs @@ -48,6 +48,7 @@ import Data.Handle (Handle, parseHandle) import Data.Id import Data.Maybe import Data.Qualified +import Data.Text qualified as T import Data.Text.Ascii (AsciiText (toText)) import Imports import Polysemy @@ -88,7 +89,7 @@ validateHandle = maybe (throwStd (errorToWai @'InvalidHandle)) pure . parseHandl logEmail :: Email -> (Msg -> Msg) logEmail email = - Log.field "email_sha256" (sha256String . cs . show $ email) + Log.field "email_sha256" (sha256String . T.pack . show $ email) logInvitationCode :: InvitationCode -> (Msg -> Msg) logInvitationCode code = Log.field "invitation_code" (toText $ fromInvitationCode code) diff --git a/services/brig/src/Brig/Calling.hs b/services/brig/src/Brig/Calling.hs index 49c79b0a9de..c9501b3fcad 100644 --- a/services/brig/src/Brig/Calling.hs +++ b/services/brig/src/Brig/Calling.hs @@ -63,6 +63,7 @@ import Data.Misc import Data.Range import Data.Text qualified as Text import Data.Text.Encoding qualified as Text +import Data.Text.Encoding.Error import Data.Text.IO qualified as Text import Data.Time.Clock (DiffTime, diffTimeToPicoseconds) import Imports @@ -343,7 +344,15 @@ startDNSBasedTurnDiscovery logger opts deprecatedUdpRef udpRef tcpRef tlsRef = d turnURIFromSRV :: Scheme -> Maybe Transport -> SrvEntry -> TurnURI turnURIFromSRV sch mtr SrvEntry {..} = - turnURI sch (TurnHostName . cs . stripDot $ srvTargetDomain srvTarget) (Port $ srvTargetPort srvTarget) mtr + turnURI + sch + ( TurnHostName + . Text.decodeUtf8With lenientDecode + . stripDot + $ srvTargetDomain srvTarget + ) + (Port $ srvTargetPort srvTarget) + mtr where stripDot h | "." `BS.isSuffixOf` h = BS.take (BS.length h - 1) h diff --git a/services/brig/src/Brig/Effects/JwtTools.hs b/services/brig/src/Brig/Effects/JwtTools.hs index e6304fb90b4..1b9a1773413 100644 --- a/services/brig/src/Brig/Effects/JwtTools.hs +++ b/services/brig/src/Brig/Effects/JwtTools.hs @@ -12,6 +12,8 @@ import Data.Jwt.Tools qualified as Jwt import Data.Misc (HttpsUrl) import Data.Nonce (Nonce) import Data.PEMKeys +import Data.Text.Encoding +import Data.Text.Encoding.Error import Imports import Network.HTTP.Types (StdMethod (..)) import Network.HTTP.Types qualified as HTTP @@ -77,4 +79,4 @@ interpretJwtTools = interpret $ \case ) where urlEncode :: Text -> Text - urlEncode = cs . HTTP.urlEncode False . cs + urlEncode = decodeUtf8With lenientDecode . HTTP.urlEncode False . encodeUtf8 diff --git a/services/brig/src/Brig/Effects/SFT.hs b/services/brig/src/Brig/Effects/SFT.hs index 24fe09bfa7d..d1cdd9d2cde 100644 --- a/services/brig/src/Brig/Effects/SFT.hs +++ b/services/brig/src/Brig/Effects/SFT.hs @@ -29,6 +29,7 @@ where import Data.Aeson qualified as Aeson import Data.ByteString.Conversion +import Data.ByteString.UTF8 qualified as UTF8 import Data.Map qualified as Map import Data.Misc import Data.Schema @@ -58,7 +59,7 @@ interpretSFT :: Members [Embed IO, TinyLog] r => Manager -> Sem (SFT ': r) a -> interpretSFT httpManager = interpret $ \(SFTGetAllServers url) -> do let urlWithPath = ensureHttpsUrl $ (httpsUrl url) {uriPath = "/sft_servers_all.json"} fmap SFTGetResponse . runSftError urlWithPath $ do - let req = parseRequest_ . cs . toByteString' $ urlWithPath + let req = parseRequest_ . UTF8.toString . toByteString' $ urlWithPath response <- fromExceptionVia @HttpException (SFTError . show) (responseBody <$> httpLbs req httpManager) let eList = Aeson.eitherDecode @AllURLs response res <- fromEither $ bimap SFTError (fmap sftServer . unAllURLs) eList @@ -92,6 +93,6 @@ interpretSFTInMemory m = interpret $ \(SFTGetAllServers url) -> case Map.lookup url m of Nothing -> do let msg = "No value in the lookup map" - err $ Log.field "url" (show url) . Log.msg (cs msg :: ByteString) + err $ Log.field "url" (show url) . Log.msg (UTF8.fromString msg :: ByteString) pure . SFTGetResponse . Left . SFTError $ msg Just ss -> pure ss diff --git a/services/brig/src/Brig/Index/Eval.hs b/services/brig/src/Brig/Index/Eval.hs index 7d4ea3f5dd8..4d8f163dfdb 100644 --- a/services/brig/src/Brig/Index/Eval.hs +++ b/services/brig/src/Brig/Index/Eval.hs @@ -32,6 +32,7 @@ import Control.Monad.Catch import Control.Retry import Data.Aeson (FromJSON) import Data.Aeson qualified as Aeson +import Data.ByteString.Lazy.UTF8 qualified as UTF8 import Data.Credentials (Credentials (..)) import Data.Metrics qualified as Metrics import Database.Bloodhound qualified as ES @@ -130,7 +131,7 @@ waitForTaskToComplete timeoutSeconds taskNodeId = do throwM $ ReindexFromAnotherIndexError $ "Task failed with error: " - <> cs (Aeson.encode $ ES.taskResponseError task) + <> UTF8.toString (Aeson.encode $ ES.taskResponseError task) where isTaskComplete :: Either ES.EsError (ES.TaskResponse a) -> m Bool isTaskComplete (Left e) = throwM $ ReindexFromAnotherIndexError $ "Error response while getting task: " <> show e diff --git a/services/brig/src/Brig/Run.hs b/services/brig/src/Brig/Run.hs index 90316762356..e7219fef819 100644 --- a/services/brig/src/Brig/Run.hs +++ b/services/brig/src/Brig/Run.hs @@ -45,11 +45,13 @@ import Control.Lens (view, (.~), (^.)) import Control.Monad.Catch (MonadCatch, finally) import Control.Monad.Random (randomRIO) import Data.Aeson qualified as Aeson +import Data.ByteString.UTF8 qualified as UTF8 import Data.Id (RequestId (..)) import Data.Metrics.AWS (gaugeTokenRemaing) import Data.Metrics.Servant qualified as Metrics import Data.Proxy (Proxy (Proxy)) import Data.Text (unpack) +import Data.Text.Encoding import Data.UUID as UUID import Data.UUID.V4 as UUID import Imports hiding (head) @@ -155,7 +157,7 @@ lookupRequestIdMiddleware logger mkapp req cont = do Just rid -> do mkapp (RequestId rid) req cont Nothing -> do - localRid <- RequestId . cs . UUID.toText <$> UUID.nextRandom + localRid <- RequestId . encodeUtf8 . UUID.toText <$> UUID.nextRandom Log.info logger $ "request-id" .= localRid ~~ "method" .= Wai.requestMethod req @@ -173,7 +175,7 @@ bodyParserErrorFormatter :: Servant.ErrorFormatter bodyParserErrorFormatter _ _ errMsg = Servant.ServerError { Servant.errHTTPCode = HTTP.statusCode HTTP.status400, - Servant.errReasonPhrase = cs $ HTTP.statusMessage HTTP.status400, + Servant.errReasonPhrase = UTF8.toString $ HTTP.statusMessage HTTP.status400, Servant.errBody = Aeson.encode $ Aeson.object @@ -218,7 +220,7 @@ pendingActivationCleanup = do safeForever funName action = forever $ action `catchAny` \exc -> do - err $ "error" .= show exc ~~ msg (val $ cs funName <> " failed") + err $ "error" .= show exc ~~ msg (val $ UTF8.fromString funName <> " failed") -- pause to keep worst-case noise in logs manageable threadDelay 60_000_000 diff --git a/services/brig/src/Brig/Team/API.hs b/services/brig/src/Brig/Team/API.hs index cb42bc6f010..c14ac164d13 100644 --- a/services/brig/src/Brig/Team/API.hs +++ b/services/brig/src/Brig/Team/API.hs @@ -56,6 +56,7 @@ import Data.Id import Data.List1 qualified as List1 import Data.Qualified (Local) import Data.Range +import Data.Text.Lazy qualified as LT import Data.Time.Clock (UTCTime) import Imports hiding (head) import Network.Wai.Utilities hiding (code, message) @@ -201,7 +202,12 @@ logInvitationRequest context action = eith <- action' case eith of Left err' -> do - Log.warn $ context . Log.msg @Text ("Failed to create invitation, label: " <> (cs . errorLabel) err') + Log.warn $ + context + . Log.msg @Text + ( "Failed to create invitation, label: " + <> (LT.toStrict . errorLabel) err' + ) pure (Left err') Right result@(_, code) -> do Log.info $ (context . logInvitationCode code) . Log.msg @Text "Successfully created invitation" diff --git a/services/brig/src/Brig/User/Auth/Cookie.hs b/services/brig/src/Brig/User/Auth/Cookie.hs index 5da62fb8e43..1bd569bc352 100644 --- a/services/brig/src/Brig/User/Auth/Cookie.hs +++ b/services/brig/src/Brig/User/Auth/Cookie.hs @@ -56,7 +56,7 @@ import Data.Metrics qualified as Metrics import Data.Proxy import Data.RetryAfter import Data.Time.Clock -import Imports hiding (cs) +import Imports import Network.Wai (Response) import Network.Wai.Utilities.Response (addHeader) import System.Logger.Class (field, msg, val, (~~)) diff --git a/services/brig/src/Brig/User/Auth/Cookie/Limit.hs b/services/brig/src/Brig/User/Auth/Cookie/Limit.hs index 5c25c4588f2..034f3ced85f 100644 --- a/services/brig/src/Brig/User/Auth/Cookie/Limit.hs +++ b/services/brig/src/Brig/User/Auth/Cookie/Limit.hs @@ -22,7 +22,7 @@ import Data.RetryAfter import Data.Time.Clock import Data.Time.Clock.POSIX import Data.Vector qualified as Vector -import Imports hiding (cs) +import Imports import Statistics.Sample qualified as Stats import Wire.API.User.Auth diff --git a/services/brig/src/Brig/User/Auth/DB/Cookie.hs b/services/brig/src/Brig/User/Auth/DB/Cookie.hs index d52dfbf1944..c0d43ef2341 100644 --- a/services/brig/src/Brig/User/Auth/DB/Cookie.hs +++ b/services/brig/src/Brig/User/Auth/DB/Cookie.hs @@ -23,7 +23,7 @@ import Brig.User.Auth.DB.Instances () import Cassandra import Data.Id import Data.Time.Clock -import Imports hiding (cs) +import Imports import Wire.API.User.Auth newtype TTL = TTL {ttlSeconds :: Int32} diff --git a/services/brig/src/Brig/User/EJPD.hs b/services/brig/src/Brig/User/EJPD.hs index 31392bfd84b..b5afec1f8f0 100644 --- a/services/brig/src/Brig/User/EJPD.hs +++ b/services/brig/src/Brig/User/EJPD.hs @@ -36,6 +36,7 @@ import Data.ByteString.Conversion import Data.Handle (Handle) import Data.Id (UserId) import Data.Set qualified as Set +import Data.Text qualified as T import Imports hiding (head) import Network.HTTP.Types.Method import Polysemy (Member) @@ -118,7 +119,7 @@ ejpdRequest (fromMaybe False -> includeContacts) (EJPDRequestBody handles) = do case (statusCode resp, responseJsonEither resp) of (200, Right (A.String loc)) -> loc _ -> - cs $ + T.pack $ "could not fetch asset: " <> show key <> ", error: " diff --git a/services/brig/src/Brig/User/Search/Index.hs b/services/brig/src/Brig/User/Search/Index.hs index b3a0b0834e5..fb0ba23c78a 100644 --- a/services/brig/src/Brig/User/Search/Index.hs +++ b/services/brig/src/Brig/User/Search/Index.hs @@ -69,6 +69,7 @@ import Control.Retry (RetryPolicy, exponentialBackoff, limitRetries, recovering) import Data.Aeson as Aeson import Data.Aeson.Encoding import Data.Aeson.Lens +import Data.ByteString (toStrict) import Data.ByteString.Builder (Builder, toLazyByteString) import Data.ByteString.Conversion (toByteString') import Data.ByteString.Conversion qualified as Bytes @@ -80,7 +81,8 @@ import Data.Map qualified as Map import Data.Metrics import Data.Text qualified as T import Data.Text qualified as Text -import Data.Text.Encoding (decodeUtf8, encodeUtf8) +import Data.Text.Encoding +import Data.Text.Encoding.Error import Data.Text.Lazy qualified as LT import Data.Text.Lazy.Builder.Int (decimal) import Data.Text.Lens hiding (text) @@ -339,7 +341,12 @@ createIndex' failIfExists (CreateIndexSettings settings shardCount mbDeleteTempl for_ mbDeleteTemplate $ \templateName@(ES.TemplateName tname) -> do tExists <- ES.templateExists templateName when tExists $ do - dr <- traceES (cs ("Delete index template " <> "\"" <> tname <> "\"")) $ ES.deleteTemplate templateName + dr <- + traceES + ( encodeUtf8 + ("Delete index template " <> "\"" <> tname <> "\"") + ) + $ ES.deleteTemplate templateName unless (ES.isSuccess dr) $ throwM (IndexError "Deleting index template failed.") @@ -895,7 +902,11 @@ reindexRowToIndexUser idpUrl (UserScimExternalId _) = Nothing fromUri :: URI -> Text - fromUri = cs . toLazyByteString . serializeURIRef + fromUri = + decodeUtf8With lenientDecode + . toStrict + . toLazyByteString + . serializeURIRef sso :: UserSSOId -> Maybe Sso sso userSsoId = do diff --git a/services/brig/src/Brig/User/Search/TeamUserSearch.hs b/services/brig/src/Brig/User/Search/TeamUserSearch.hs index 9722be1ad74..90bcb969e96 100644 --- a/services/brig/src/Brig/User/Search/TeamUserSearch.hs +++ b/services/brig/src/Brig/User/Search/TeamUserSearch.hs @@ -33,6 +33,7 @@ import Brig.User.Search.Index import Control.Error (lastMay) import Control.Monad.Catch (MonadThrow (throwM)) import Data.Aeson (decode', encode) +import Data.ByteString (fromStrict, toStrict) import Data.Id (TeamId, idToText) import Data.Range (Range (..)) import Data.Text.Ascii (decodeBase64Url, encodeBase64Url) @@ -66,10 +67,10 @@ teamUserSearch tid mbSearchText mRoleFilter mSortBy mSortOrder (fromRange -> siz either (throwM . IndexLookupError) (pure . mkResult) r where toSearchAfterKey :: PagingState -> Maybe ES.SearchAfterKey - toSearchAfterKey ps = decode' . cs =<< (decodeBase64Url . unPagingState $ ps) + toSearchAfterKey ps = decode' . fromStrict =<< (decodeBase64Url . unPagingState $ ps) fromSearchAfterKey :: ES.SearchAfterKey -> PagingState - fromSearchAfterKey = PagingState . encodeBase64Url . cs . encode + fromSearchAfterKey = PagingState . encodeBase64Url . toStrict . encode mkResult es = let hitsPlusOne = ES.hits . ES.searchHits $ es diff --git a/services/brig/test/integration/API/Calling.hs b/services/brig/test/integration/API/Calling.hs index b6a355b1264..c8008d01cb6 100644 --- a/services/brig/test/integration/API/Calling.hs +++ b/services/brig/test/integration/API/Calling.hs @@ -33,6 +33,7 @@ import Data.List.NonEmpty (NonEmpty ((:|))) import Data.List.NonEmpty qualified as NonEmpty import Data.Misc (Port (..), mkHttpsUrl) import Data.Set qualified as Set +import Data.String.Conversions import Imports import System.FilePath (()) import Test.Tasty diff --git a/services/brig/test/integration/API/Internal/Util.hs b/services/brig/test/integration/API/Internal/Util.hs index 733c23620b2..b37bff338a2 100644 --- a/services/brig/test/integration/API/Internal/Util.hs +++ b/services/brig/test/integration/API/Internal/Util.hs @@ -31,6 +31,7 @@ import Control.Lens ((^.)) import Control.Monad.Catch (MonadCatch) import Data.Id import Data.Proxy (Proxy (Proxy)) +import Data.String.Conversions import Imports import Servant.API ((:>)) import Servant.API.ContentTypes (NoContent) diff --git a/services/brig/test/integration/API/OAuth.hs b/services/brig/test/integration/API/OAuth.hs index 162a920b431..cd08aae8317 100644 --- a/services/brig/test/integration/API/OAuth.hs +++ b/services/brig/test/integration/API/OAuth.hs @@ -37,6 +37,7 @@ import Data.Id import Data.Qualified (Qualified (qUnqualified)) import Data.Range import Data.Set as Set hiding (delete, null, (\\)) +import Data.String.Conversions import Data.Text.Ascii (encodeBase16) import Data.Text.Encoding qualified as T import Data.Time diff --git a/services/brig/test/integration/API/Search.hs b/services/brig/test/integration/API/Search.hs index 4a1e359149d..43216781b57 100644 --- a/services/brig/test/integration/API/Search.hs +++ b/services/brig/test/integration/API/Search.hs @@ -43,6 +43,7 @@ import Data.Handle (fromHandle) import Data.Id import Data.Map.Strict qualified as Map import Data.Qualified (Qualified (qDomain, qUnqualified)) +import Data.String.Conversions import Data.Text qualified as Text import Data.Text.Encoding qualified as Text import Database.Bloodhound qualified as ES diff --git a/services/brig/test/integration/API/Search/Util.hs b/services/brig/test/integration/API/Search/Util.hs index 10e738a0eab..3141b4be83f 100644 --- a/services/brig/test/integration/API/Search/Util.hs +++ b/services/brig/test/integration/API/Search/Util.hs @@ -26,6 +26,7 @@ import Data.Domain (Domain) import Data.Id import Data.Qualified (Qualified (..)) import Data.Range (Range) +import Data.String.Conversions import Data.Text.Encoding (encodeUtf8) import Database.Bloodhound qualified as ES import Imports diff --git a/services/brig/test/integration/API/SystemSettings.hs b/services/brig/test/integration/API/SystemSettings.hs index 1b2f600140c..40b20c0606f 100644 --- a/services/brig/test/integration/API/SystemSettings.hs +++ b/services/brig/test/integration/API/SystemSettings.hs @@ -24,6 +24,7 @@ import Control.Lens import Data.ByteString.Char8 qualified as BS import Data.ByteString.Conversion (toByteString') import Data.Id +import Data.String.Conversions import Imports import Network.Wai.Test as WaiTest import Test.Tasty diff --git a/services/brig/test/integration/API/TeamUserSearch.hs b/services/brig/test/integration/API/TeamUserSearch.hs index c939dc5d16c..84e2a8a3701 100644 --- a/services/brig/test/integration/API/TeamUserSearch.hs +++ b/services/brig/test/integration/API/TeamUserSearch.hs @@ -28,6 +28,7 @@ import Data.ByteString.Conversion (toByteString) import Data.Handle (fromHandle) import Data.Id (TeamId, UserId) import Data.Range (unsafeRange) +import Data.String.Conversions import Imports import System.Random.Shuffle (shuffleM) import Test.Tasty (TestTree, testGroup) diff --git a/services/brig/test/integration/API/User/Account.hs b/services/brig/test/integration/API/User/Account.hs index 4d82aa1382f..66254e93fa1 100644 --- a/services/brig/test/integration/API/User/Account.hs +++ b/services/brig/test/integration/API/User/Account.hs @@ -57,6 +57,7 @@ import Data.Proxy import Data.Qualified import Data.Range import Data.Set qualified as Set +import Data.String.Conversions import Data.Text qualified as T import Data.Text qualified as Text import Data.Text.Encoding qualified as T diff --git a/services/brig/test/integration/API/User/Auth.hs b/services/brig/test/integration/API/User/Auth.hs index 3e59633e2d2..a52cd738b41 100644 --- a/services/brig/test/integration/API/User/Auth.hs +++ b/services/brig/test/integration/API/User/Auth.hs @@ -53,7 +53,7 @@ import Data.Text.Lazy qualified as Lazy import Data.Time.Clock import Data.UUID.V4 qualified as UUID import Data.ZAuth.Token qualified as ZAuth -import Imports hiding (cs) +import Imports import Network.HTTP.Client (equivCookie) import Network.Wai.Utilities.Error qualified as Error import Test.Tasty diff --git a/services/brig/test/integration/API/User/Client.hs b/services/brig/test/integration/API/User/Client.hs index 3372c1b3e56..df4b7c5faaa 100644 --- a/services/brig/test/integration/API/User/Client.hs +++ b/services/brig/test/integration/API/User/Client.hs @@ -52,6 +52,7 @@ import Data.Nonce (isValidBase64UrlEncodedUUID) import Data.Qualified (Qualified (..)) import Data.Range (unsafeRange) import Data.Set qualified as Set +import Data.String.Conversions import Data.Text.Ascii (AsciiChars (validate), encodeBase64UrlUnpadded, toText) import Data.Text.Encoding qualified as T import Data.Time (addUTCTime) diff --git a/services/brig/test/integration/API/User/PasswordReset.hs b/services/brig/test/integration/API/User/PasswordReset.hs index 26f1b5c41e4..55f19b34c28 100644 --- a/services/brig/test/integration/API/User/PasswordReset.hs +++ b/services/brig/test/integration/API/User/PasswordReset.hs @@ -30,7 +30,7 @@ import Cassandra qualified as DB import Data.Aeson as A import Data.Aeson.KeyMap qualified as KeyMap import Data.Misc -import Imports hiding (cs) +import Imports import Test.Tasty hiding (Timeout) import Util import Wire.API.User diff --git a/services/brig/test/integration/API/User/Property.hs b/services/brig/test/integration/API/User/Property.hs index e87733c5d2d..fd16f35793f 100644 --- a/services/brig/test/integration/API/User/Property.hs +++ b/services/brig/test/integration/API/User/Property.hs @@ -27,6 +27,7 @@ import Brig.Options import Brig.Options qualified as Opt import Data.Aeson import Data.ByteString.Char8 qualified as C +import Data.String.Conversions import Data.Text qualified as T import Imports import Network.Wai.Utilities.Error qualified as Error diff --git a/services/brig/test/integration/API/User/Util.hs b/services/brig/test/integration/API/User/Util.hs index 031a521e504..dfd26fb1c26 100644 --- a/services/brig/test/integration/API/User/Util.hs +++ b/services/brig/test/integration/API/User/Util.hs @@ -47,6 +47,7 @@ import Data.List1 qualified as List1 import Data.Misc import Data.Qualified import Data.Range (unsafeRange) +import Data.String.Conversions import Data.Text.Ascii qualified as Ascii import Data.Vector qualified as Vec import Data.ZAuth.Token qualified as ZAuth diff --git a/services/brig/test/integration/API/UserPendingActivation.hs b/services/brig/test/integration/API/UserPendingActivation.hs index 0537b2af448..db47762b6e4 100644 --- a/services/brig/test/integration/API/UserPendingActivation.hs +++ b/services/brig/test/integration/API/UserPendingActivation.hs @@ -36,6 +36,7 @@ import Data.Aeson.Lens (key, _String) import Data.ByteString.Conversion (fromByteString, toByteString') import Data.Id (InvitationId, TeamId, UserId) import Data.Range (unsafeRange) +import Data.String.Conversions import Data.Text.Encoding (encodeUtf8) import Data.UUID qualified as UUID import Data.UUID.V4 qualified as UUID diff --git a/services/brig/test/integration/Federation/End2end.hs b/services/brig/test/integration/Federation/End2end.hs index b696338e0fe..cf1beffc23c 100644 --- a/services/brig/test/integration/Federation/End2end.hs +++ b/services/brig/test/integration/Federation/End2end.hs @@ -38,7 +38,7 @@ import Data.Qualified import Data.Range (checked) import Data.Set qualified as Set import Federation.Util -import Imports hiding (cs) +import Imports import System.IO.Temp import System.Logger qualified as Log import Test.Tasty diff --git a/services/brig/test/integration/Util.hs b/services/brig/test/integration/Util.hs index 46b8aa917c3..c75d25fe2c1 100644 --- a/services/brig/test/integration/Util.hs +++ b/services/brig/test/integration/Util.hs @@ -61,6 +61,7 @@ import Data.Proxy import Data.Qualified hiding (isLocal) import Data.Range import Data.Sequence qualified as Seq +import Data.String.Conversions import Data.Text qualified as T import Data.Text qualified as Text import Data.Text.Ascii qualified as Ascii diff --git a/services/cannon/src/Cannon/Types.hs b/services/cannon/src/Cannon/Types.hs index 63dbdb42c37..9dc29f2e2e8 100644 --- a/services/cannon/src/Cannon/Types.hs +++ b/services/cannon/src/Cannon/Types.hs @@ -126,7 +126,7 @@ lookupReqId :: Logger -> Request -> IO RequestId lookupReqId l r = case lookup requestIdName (requestHeaders r) of Just rid -> pure $ RequestId rid Nothing -> do - localRid <- RequestId . cs . UUID.toText <$> UUID.nextRandom + localRid <- RequestId . UUID.toASCIIBytes <$> UUID.nextRandom Log.info l $ "request-id" .= localRid ~~ "method" .= requestMethod r diff --git a/services/cannon/src/Cannon/WS.hs b/services/cannon/src/Cannon/WS.hs index 1cc3b3aaa84..6837457b636 100644 --- a/services/cannon/src/Cannon/WS.hs +++ b/services/cannon/src/Cannon/WS.hs @@ -67,7 +67,7 @@ import Data.List.Extra (chunksOf) import Data.Text.Encoding (decodeUtf8) import Data.Timeout (TimeoutUnit (..), (#)) import Gundeck.Types -import Imports hiding (cs, threadDelay) +import Imports hiding (threadDelay) import Network.HTTP.Types.Method import Network.HTTP.Types.Status import Network.Wai.Utilities.Error diff --git a/services/cargohold/src/CargoHold/API/Public.hs b/services/cargohold/src/CargoHold/API/Public.hs index 0430c110ef3..794e4ae0318 100644 --- a/services/cargohold/src/CargoHold/API/Public.hs +++ b/services/cargohold/src/CargoHold/API/Public.hs @@ -33,6 +33,8 @@ import Data.Domain import Data.Id import Data.Kind import Data.Qualified +import Data.Text.Encoding +import Data.Text.Encoding.Error import Imports hiding (head) import qualified Network.HTTP.Types as HTTP import Servant.API @@ -88,7 +90,11 @@ iDownloadAssetV3 key = do where -- (NB: don't use HttpsUrl here, as in some test environments we legitimately use "http"!) render :: URI.URI -> Text - render = cs . Builder.toLazyByteString . URI.serializeURIRef + render = + decodeUtf8With lenientDecode + . LBS.toStrict + . Builder.toLazyByteString + . URI.serializeURIRef class HasLocation (tag :: PrincipalTag) where assetLocation :: Local AssetKey -> [Text] diff --git a/services/cargohold/src/CargoHold/Run.hs b/services/cargohold/src/CargoHold/Run.hs index be0228da1ef..2a7165e162d 100644 --- a/services/cargohold/src/CargoHold/Run.hs +++ b/services/cargohold/src/CargoHold/Run.hs @@ -104,7 +104,7 @@ mkApp o = Codensity $ \k -> lookupReqId l r = case lookup requestIdName $ Wai.requestHeaders r of Just rid -> pure $ RequestId rid Nothing -> do - localRid <- RequestId . cs . UUID.toText <$> UUID.nextRandom + localRid <- RequestId . UUID.toASCIIBytes <$> UUID.nextRandom Log.info l $ "request-id" .= localRid ~~ "method" .= Wai.requestMethod r diff --git a/services/federator/default.nix b/services/federator/default.nix index 5cb5b5b2830..423926f9509 100644 --- a/services/federator/default.nix +++ b/services/federator/default.nix @@ -52,6 +52,7 @@ , servant-client , servant-client-core , servant-server +, string-conversions , tasty , tasty-hunit , tasty-quickcheck @@ -61,6 +62,7 @@ , transformers , types-common , unix +, utf8-string , uuid , wai , wai-extra @@ -120,6 +122,7 @@ mkDerivation { transformers types-common unix + utf8-string uuid wai wai-utilities @@ -154,6 +157,7 @@ mkDerivation { QuickCheck random servant-client-core + string-conversions tasty-hunit text types-common @@ -188,6 +192,7 @@ mkDerivation { servant-client servant-client-core servant-server + string-conversions tasty tasty-hunit tasty-quickcheck diff --git a/services/federator/federator.cabal b/services/federator/federator.cabal index 0a0767edeb2..4fa411b3be0 100644 --- a/services/federator/federator.cabal +++ b/services/federator/federator.cabal @@ -147,6 +147,7 @@ library , transformers , types-common , unix + , utf8-string , uuid , wai , wai-utilities @@ -303,6 +304,7 @@ executable federator-integration , QuickCheck , random , servant-client-core + , string-conversions , tasty-hunit , text , types-common @@ -404,6 +406,7 @@ test-suite federator-tests , servant-client , servant-client-core , servant-server + , string-conversions , tasty , tasty-hunit , tasty-quickcheck diff --git a/services/federator/src/Federator/Discovery.hs b/services/federator/src/Federator/Discovery.hs index 9050125e68c..901042f86ba 100644 --- a/services/federator/src/Federator/Discovery.hs +++ b/services/federator/src/Federator/Discovery.hs @@ -96,7 +96,7 @@ runFederatorDiscovery = interpret $ \case -- FUTUREWORK(federation): This string conversion is wrong, we should encode -- this using IDNA encoding or expect domain to be bytestring everywhere -- (https://wearezeta.atlassian.net/browse/SQCORE-912) - domainSrv d = cs $ "_wire-server-federator._tcp." <> domainText d + domainSrv d = Text.encodeUtf8 $ "_wire-server-federator._tcp." <> domainText d lookupDomainByDNS :: ( Member DNSLookup r, diff --git a/services/federator/src/Federator/ExternalServer.hs b/services/federator/src/Federator/ExternalServer.hs index 513bf5d73e8..4a2f83d4c5f 100644 --- a/services/federator/src/Federator/ExternalServer.hs +++ b/services/federator/src/Federator/ExternalServer.hs @@ -148,7 +148,7 @@ callInward component (RPC rpc) mReqId originDomain (CertHeader cert) wreq = do rid <- case mReqId of Just r -> pure r Nothing -> do - localRid <- liftIO $ RequestId . cs . UUID.toText <$> UUID.nextRandom + localRid <- liftIO $ RequestId . Text.encodeUtf8 . UUID.toText <$> UUID.nextRandom info $ "request-id" .= localRid ~~ "method" .= Wai.requestMethod wreq diff --git a/services/federator/src/Federator/Health.hs b/services/federator/src/Federator/Health.hs index 7a2228b74d0..857a3e56415 100644 --- a/services/federator/src/Federator/Health.hs +++ b/services/federator/src/Federator/Health.hs @@ -1,5 +1,7 @@ module Federator.Health where +import Data.ByteString (fromStrict) +import Data.ByteString.UTF8 qualified as UTF8 import Imports import Network.HTTP.Client import Network.HTTP.Types.Status qualified as HTTP @@ -20,4 +22,11 @@ status mgr otherName otherPort False = do res <- liftIO $ httpNoBody req mgr if HTTP.statusIsSuccessful $ responseStatus res then pure NoContent - else throwError Servant.err500 {Servant.errBody = otherName <> " server responded with status code = " <> cs (show (responseStatus res))} + else + throwError + Servant.err500 + { Servant.errBody = + otherName + <> " server responded with status code = " + <> (fromStrict . UTF8.fromString . show . responseStatus $ res) + } diff --git a/services/federator/src/Federator/InternalServer.hs b/services/federator/src/Federator/InternalServer.hs index 13dd401f3b6..ef6cbd0cce4 100644 --- a/services/federator/src/Federator/InternalServer.hs +++ b/services/federator/src/Federator/InternalServer.hs @@ -27,6 +27,7 @@ import Data.Domain import Data.Id import Data.Metrics.Servant qualified as Metrics import Data.Proxy +import Data.Text.Encoding qualified as T import Data.UUID as UUID import Data.UUID.V4 as UUID import Federator.Env @@ -117,7 +118,7 @@ callOutward mReqId targetDomain component (RPC path) req = do rid <- case mReqId of Just r -> pure r Nothing -> do - localRid <- liftIO $ RequestId . cs . UUID.toText <$> UUID.nextRandom + localRid <- liftIO $ RequestId . T.encodeUtf8 . UUID.toText <$> UUID.nextRandom info $ "request-id" .= localRid ~~ "method" .= Wai.requestMethod req diff --git a/services/federator/src/Federator/Response.hs b/services/federator/src/Federator/Response.hs index 04662a1da3a..6f70df5a390 100644 --- a/services/federator/src/Federator/Response.hs +++ b/services/federator/src/Federator/Response.hs @@ -29,6 +29,7 @@ import Control.Lens import Control.Monad.Codensity import Data.ByteString.Builder import Data.Kind +import Data.Text qualified as T import Federator.Discovery import Federator.Env import Federator.Error @@ -172,7 +173,7 @@ getFederationDomainConfigs :: Env -> IO FedUp.FederationDomainConfigs getFederationDomainConfigs env = do let mgr = env ^. httpManager Endpoint h p = env ^. service $ Brig - baseurl = BaseUrl Http (cs h) (fromIntegral p) "" + baseurl = BaseUrl Http (T.unpack h) (fromIntegral p) "" clientEnv = mkClientEnv mgr baseurl FedUp.getFederationDomainConfigs clientEnv >>= \case Right v -> pure v diff --git a/services/federator/src/Federator/Service.hs b/services/federator/src/Federator/Service.hs index 691f4629dff..b4f859d52bf 100644 --- a/services/federator/src/Federator/Service.hs +++ b/services/federator/src/Federator/Service.hs @@ -94,7 +94,7 @@ interpretServiceHTTP = interpret $ \case path = rpcPath, requestHeaders = [ ("Content-Type", "application/json"), - (originDomainHeaderName, cs (domainText domain)), + (originDomainHeaderName, Text.encodeUtf8 (domainText domain)), (RPC.requestIdName, unRequestId rid) ] <> headers diff --git a/services/federator/test/integration/Test/Federator/IngressSpec.hs b/services/federator/test/integration/Test/Federator/IngressSpec.hs index e8eb7151c7e..62b4f1b7401 100644 --- a/services/federator/test/integration/Test/Federator/IngressSpec.hs +++ b/services/federator/test/integration/Test/Federator/IngressSpec.hs @@ -25,6 +25,7 @@ import Data.Binary.Builder import Data.Domain import Data.Id import Data.LegalHold (UserLegalHoldStatus (UserLegalHoldNoConsent)) +import Data.String.Conversions import Data.Text.Encoding qualified as Text import Federator.Discovery import Federator.Monitor (FederationSetupError) diff --git a/services/federator/test/integration/Test/Federator/Util.hs b/services/federator/test/integration/Test/Federator/Util.hs index 6d8a61f0093..549590cb6af 100644 --- a/services/federator/test/integration/Test/Federator/Util.hs +++ b/services/federator/test/integration/Test/Federator/Util.hs @@ -37,6 +37,7 @@ import Data.Aeson.Types qualified as Aeson import Data.ByteString.Char8 qualified as C8 import Data.Id import Data.Misc +import Data.String.Conversions import Data.Text qualified as Text import Data.UUID qualified as UUID import Data.UUID.V4 qualified as UUID diff --git a/services/federator/test/unit/Test/Federator/ExternalServer.hs b/services/federator/test/unit/Test/Federator/ExternalServer.hs index 48680d09d33..ec0b0438e24 100644 --- a/services/federator/test/unit/Test/Federator/ExternalServer.hs +++ b/services/federator/test/unit/Test/Federator/ExternalServer.hs @@ -24,6 +24,7 @@ import Data.ByteString qualified as BS import Data.Default import Data.Domain import Data.Sequence as Seq +import Data.String.Conversions import Data.Text.Encoding qualified as Text import Federator.Discovery import Federator.Error.ServerError (ServerError (..)) diff --git a/services/galley/default.nix b/services/galley/default.nix index 279ee871813..3e82122d703 100644 --- a/services/galley/default.nix +++ b/services/galley/default.nix @@ -89,6 +89,7 @@ , ssl-util , stm , streaming-commons +, string-conversions , tagged , tasty , tasty-ant-xml @@ -109,6 +110,7 @@ , unliftio , unordered-containers , uri-bytestring +, utf8-string , uuid , uuid-types , vector @@ -206,6 +208,7 @@ mkDerivation { types-common-journal unliftio uri-bytestring + utf8-string uuid wai wai-extra @@ -281,6 +284,7 @@ mkDerivation { sop-core ssl-util streaming-commons + string-conversions tagged tasty tasty-ant-xml diff --git a/services/galley/galley.cabal b/services/galley/galley.cabal index 91556478195..58ae6271940 100644 --- a/services/galley/galley.cabal +++ b/services/galley/galley.cabal @@ -357,6 +357,7 @@ library , types-common-journal >=0.1 , unliftio >=0.2 , uri-bytestring >=0.2 + , utf8-string , uuid >=1.3 , wai >=3.0 , wai-extra >=3.0 @@ -527,6 +528,7 @@ executable galley-integration , sop-core , ssl-util , streaming-commons + , string-conversions , tagged , tasty >=0.8 , tasty-ant-xml diff --git a/services/galley/src/Galley/API/Internal.hs b/services/galley/src/Galley/API/Internal.hs index 5e66acec806..c2a12f98315 100644 --- a/services/galley/src/Galley/API/Internal.hs +++ b/services/galley/src/Galley/API/Internal.hs @@ -26,6 +26,7 @@ where import Control.Exception.Safe (catchAny) import Control.Lens hiding (Getter, Setter, (.=)) +import Data.ByteString.UTF8 qualified as UTF8 import Data.Id as Id import Data.Json.Util (ToJSONObject (toJSONObject)) import Data.Map qualified as Map @@ -453,7 +454,7 @@ safeForever :: String -> App () -> App () safeForever funName action = forever $ action `catchAny` \exc -> do - err $ "error" .= show exc ~~ msg (val $ cs funName <> " failed") + err $ "error" .= show exc ~~ msg (val $ UTF8.fromString funName <> " failed") threadDelay 60000000 -- pause to keep worst-case noise in logs manageable guardLegalholdPolicyConflictsH :: diff --git a/services/galley/src/Galley/API/MLS/Commit/ExternalCommit.hs b/services/galley/src/Galley/API/MLS/Commit/ExternalCommit.hs index 484f5812332..364feaf5ce2 100644 --- a/services/galley/src/Galley/API/MLS/Commit/ExternalCommit.hs +++ b/services/galley/src/Galley/API/MLS/Commit/ExternalCommit.hs @@ -33,7 +33,7 @@ import Galley.API.MLS.Types import Galley.API.MLS.Util import Galley.Effects import Galley.Effects.MemberStore -import Imports hiding (cs) +import Imports import Polysemy import Polysemy.Error import Polysemy.Resource (Resource) diff --git a/services/galley/src/Galley/API/MLS/One2One.hs b/services/galley/src/Galley/API/MLS/One2One.hs index f0632f737c5..a5b01e129a3 100644 --- a/services/galley/src/Galley/API/MLS/One2One.hs +++ b/services/galley/src/Galley/API/MLS/One2One.hs @@ -30,7 +30,7 @@ import Galley.API.MLS.Types import Galley.Data.Conversation.Types qualified as Data import Galley.Effects.ConversationStore import Galley.Types.UserList -import Imports hiding (cs) +import Imports import Polysemy import Wire.API.Conversation hiding (Member) import Wire.API.Conversation.Protocol diff --git a/services/galley/src/Galley/API/MLS/Proposal.hs b/services/galley/src/Galley/API/MLS/Proposal.hs index 9047db2a946..4df31ac4c97 100644 --- a/services/galley/src/Galley/API/MLS/Proposal.hs +++ b/services/galley/src/Galley/API/MLS/Proposal.hs @@ -48,7 +48,7 @@ import Galley.Effects.BrigAccess import Galley.Effects.ProposalStore import Galley.Env import Galley.Options -import Imports hiding (cs) +import Imports import Polysemy import Polysemy.Error import Polysemy.Input diff --git a/services/galley/src/Galley/API/MLS/Removal.hs b/services/galley/src/Galley/API/MLS/Removal.hs index f8491cdba47..ce7f4c97f38 100644 --- a/services/galley/src/Galley/API/MLS/Removal.hs +++ b/services/galley/src/Galley/API/MLS/Removal.hs @@ -42,7 +42,7 @@ import Galley.Effects.ProposalStore import Galley.Effects.SubConversationStore import Galley.Env import Galley.Types.Conversations.Members -import Imports hiding (cs) +import Imports import Polysemy import Polysemy.Error import Polysemy.Input diff --git a/services/galley/src/Galley/API/MLS/SubConversation.hs b/services/galley/src/Galley/API/MLS/SubConversation.hs index ba13a24757b..b78d8965a8b 100644 --- a/services/galley/src/Galley/API/MLS/SubConversation.hs +++ b/services/galley/src/Galley/API/MLS/SubConversation.hs @@ -50,7 +50,7 @@ import Galley.Effects import Galley.Effects.FederatorAccess import Galley.Effects.MemberStore qualified as Eff import Galley.Effects.SubConversationStore qualified as Eff -import Imports hiding (cs) +import Imports import Polysemy import Polysemy.Error import Polysemy.Input diff --git a/services/galley/src/Galley/API/MLS/Types.hs b/services/galley/src/Galley/API/MLS/Types.hs index 13a14d9b6a4..5cfce7bd88a 100644 --- a/services/galley/src/Galley/API/MLS/Types.hs +++ b/services/galley/src/Galley/API/MLS/Types.hs @@ -27,7 +27,7 @@ import Data.Qualified import GHC.Records (HasField (..)) import Galley.Data.Conversation.Types import Galley.Types.Conversations.Members -import Imports hiding (cs) +import Imports import Wire.API.Conversation import Wire.API.Conversation.Protocol import Wire.API.MLS.CipherSuite diff --git a/services/galley/src/Galley/API/MLS/Welcome.hs b/services/galley/src/Galley/API/MLS/Welcome.hs index 188d73e6d0d..6f051263247 100644 --- a/services/galley/src/Galley/API/MLS/Welcome.hs +++ b/services/galley/src/Galley/API/MLS/Welcome.hs @@ -34,7 +34,7 @@ import Galley.API.Push import Galley.Effects.ExternalAccess import Galley.Effects.FederatorAccess import Gundeck.Types.Push.V2 (RecipientClients (..)) -import Imports hiding (cs) +import Imports import Network.Wai.Utilities.JSONResponse import Polysemy import Polysemy.Input diff --git a/services/galley/src/Galley/API/Query.hs b/services/galley/src/Galley/API/Query.hs index aaa01a9daa4..950099e7680 100644 --- a/services/galley/src/Galley/API/Query.hs +++ b/services/galley/src/Galley/API/Query.hs @@ -79,7 +79,7 @@ import Galley.Env import Galley.Options import Galley.Types.Conversations.Members import Galley.Types.Teams -import Imports hiding (cs) +import Imports import Network.Wai import Network.Wai.Predicate hiding (Error, result, setStatus) import Network.Wai.Utilities hiding (Error) diff --git a/services/galley/src/Galley/API/Teams/Features.hs b/services/galley/src/Galley/API/Teams/Features.hs index e9085fca925..06c7a09d3d0 100644 --- a/services/galley/src/Galley/API/Teams/Features.hs +++ b/services/galley/src/Galley/API/Teams/Features.hs @@ -38,6 +38,7 @@ where import Control.Lens import Data.ByteString.Conversion (toByteString') +import Data.ByteString.UTF8 qualified as UTF8 import Data.Id import Data.Json.Util import Data.Kind @@ -204,7 +205,7 @@ pushFeatureConfigEvent tid event = do P.warn $ Log.field "action" (Log.val "Features.pushFeatureConfigEvent") . Log.field "feature" (Log.val (toByteString' . Event._eventFeatureName $ event)) - . Log.field "team" (Log.val (cs . show $ tid)) + . Log.field "team" (Log.val (UTF8.fromString . show $ tid)) . Log.msg @Text "Fanout limit exceeded. Events will not be sent." else do let recipients = membersToRecipients Nothing (memList ^. teamMembers) diff --git a/services/galley/src/Galley/Cassandra/Conversation.hs b/services/galley/src/Galley/Cassandra/Conversation.hs index 286fd4b3264..e685085b0a0 100644 --- a/services/galley/src/Galley/Cassandra/Conversation.hs +++ b/services/galley/src/Galley/Cassandra/Conversation.hs @@ -48,7 +48,7 @@ import Galley.Effects.ConversationStore (ConversationStore (..)) import Galley.Types.Conversations.Members import Galley.Types.ToUserRole import Galley.Types.UserList -import Imports hiding (cs) +import Imports import Polysemy import Polysemy.Input import Polysemy.TinyLog diff --git a/services/galley/src/Galley/Cassandra/Conversation/Members.hs b/services/galley/src/Galley/Cassandra/Conversation/Members.hs index 2bda5331335..4b0482f712b 100644 --- a/services/galley/src/Galley/Cassandra/Conversation/Members.hs +++ b/services/galley/src/Galley/Cassandra/Conversation/Members.hs @@ -44,7 +44,7 @@ import Galley.Effects.MemberStore (MemberStore (..)) import Galley.Types.Conversations.Members import Galley.Types.ToUserRole import Galley.Types.UserList -import Imports hiding (Set, cs) +import Imports hiding (Set) import Polysemy import Polysemy.Input import Polysemy.TinyLog diff --git a/services/galley/src/Galley/Cassandra/Store.hs b/services/galley/src/Galley/Cassandra/Store.hs index a25fa5ab289..16794523557 100644 --- a/services/galley/src/Galley/Cassandra/Store.hs +++ b/services/galley/src/Galley/Cassandra/Store.hs @@ -21,7 +21,7 @@ module Galley.Cassandra.Store where import Cassandra -import Imports hiding (cs) +import Imports import Polysemy import Polysemy.Input diff --git a/services/galley/src/Galley/Cassandra/SubConversation.hs b/services/galley/src/Galley/Cassandra/SubConversation.hs index 687c904402a..4a00cf0a29e 100644 --- a/services/galley/src/Galley/Cassandra/SubConversation.hs +++ b/services/galley/src/Galley/Cassandra/SubConversation.hs @@ -33,7 +33,7 @@ import Galley.Cassandra.Queries qualified as Cql import Galley.Cassandra.Store (embedClient) import Galley.Cassandra.Util import Galley.Effects.SubConversationStore (SubConversationStore (..)) -import Imports hiding (cs) +import Imports import Polysemy import Polysemy.Input import Polysemy.TinyLog diff --git a/services/galley/src/Galley/Intra/User.hs b/services/galley/src/Galley/Intra/User.hs index 01c1dc64ccd..27b3497afae 100644 --- a/services/galley/src/Galley/Intra/User.hs +++ b/services/galley/src/Galley/Intra/User.hs @@ -46,6 +46,7 @@ import Data.ByteString.Char8 qualified as BSC import Data.ByteString.Conversion import Data.Id import Data.Qualified +import Data.Text qualified as Text import Data.Text.Lazy qualified as Lazy import Galley.API.Error import Galley.Env @@ -253,11 +254,11 @@ runHereClientM action = do mgr <- view manager brigep <- view brig let env = Client.mkClientEnv mgr baseurl - baseurl = Client.BaseUrl Client.Http (cs $ brigep ^. host) (fromIntegral $ brigep ^. port) "" + baseurl = Client.BaseUrl Client.Http (Text.unpack $ brigep ^. host) (fromIntegral $ brigep ^. port) "" liftIO $ Client.runClientM action env handleServantResp :: Either Client.ClientError a -> App a handleServantResp (Right cfg) = pure cfg -handleServantResp (Left errmsg) = throwM . internalErrorWithDescription . cs . show $ errmsg +handleServantResp (Left errmsg) = throwM . internalErrorWithDescription . Lazy.pack . show $ errmsg diff --git a/services/galley/src/Galley/Monad.hs b/services/galley/src/Galley/Monad.hs index c9be145a29e..1780f3d827c 100644 --- a/services/galley/src/Galley/Monad.hs +++ b/services/galley/src/Galley/Monad.hs @@ -26,7 +26,7 @@ import Control.Lens import Control.Monad.Catch import Control.Monad.Except import Galley.Env -import Imports hiding (cs, log) +import Imports hiding (log) import Polysemy import Polysemy.Input import System.Logger diff --git a/services/galley/src/Galley/Run.hs b/services/galley/src/Galley/Run.hs index 592ad9f3ed8..744e9dc4220 100644 --- a/services/galley/src/Galley/Run.hs +++ b/services/galley/src/Galley/Run.hs @@ -32,6 +32,7 @@ import Control.Exception (finally) import Control.Lens (view, (.~), (^.)) import Control.Monad.Codensity import Data.Aeson qualified as Aeson +import Data.ByteString.UTF8 qualified as UTF8 import Data.Id import Data.Metrics (Metrics) import Data.Metrics.AWS (gaugeTokenRemaing) @@ -133,7 +134,7 @@ mkApp opts = lookupReqId l r = case lookup requestIdName $ requestHeaders r of Just rid -> pure $ RequestId rid Nothing -> do - localRid <- RequestId . cs . UUID.toText <$> UUID.nextRandom + localRid <- RequestId . UUID.toASCIIBytes <$> UUID.nextRandom Log.info l $ "request-id" .= localRid ~~ "method" .= requestMethod r @@ -155,7 +156,7 @@ bodyParserErrorFormatter' :: Servant.ErrorFormatter bodyParserErrorFormatter' _ _ errMsg = Servant.ServerError { Servant.errHTTPCode = HTTP.statusCode HTTP.status400, - Servant.errReasonPhrase = cs $ HTTP.statusMessage HTTP.status400, + Servant.errReasonPhrase = UTF8.toString $ HTTP.statusMessage HTTP.status400, Servant.errBody = Aeson.encode $ Aeson.object diff --git a/services/galley/test/integration/API/Federation/Util.hs b/services/galley/test/integration/API/Federation/Util.hs index 9d15edc5ee9..9f2f052365c 100644 --- a/services/galley/test/integration/API/Federation/Util.hs +++ b/services/galley/test/integration/API/Federation/Util.hs @@ -29,6 +29,7 @@ where import Data.Kind import Data.Qualified import Data.SOP +import Data.String.Conversions import GHC.TypeLits import Imports import Servant diff --git a/services/galley/test/integration/API/Teams/LegalHold/Util.hs b/services/galley/test/integration/API/Teams/LegalHold/Util.hs index fec9706579b..85e2e37d195 100644 --- a/services/galley/test/integration/API/Teams/LegalHold/Util.hs +++ b/services/galley/test/integration/API/Teams/LegalHold/Util.hs @@ -30,6 +30,7 @@ import Data.List1 qualified as List1 import Data.Misc (PlainTextPassword6) import Data.PEM import Data.Streaming.Network (bindRandomPortTCP) +import Data.String.Conversions import Data.Tagged import Data.Text.Encoding (encodeUtf8) import Galley.Options diff --git a/services/galley/test/integration/API/Util.hs b/services/galley/test/integration/API/Util.hs index 936548d6363..5f80a490368 100644 --- a/services/galley/test/integration/API/Util.hs +++ b/services/galley/test/integration/API/Util.hs @@ -65,6 +65,7 @@ import Data.Range import Data.Serialize (runPut) import Data.Set qualified as Set import Data.Singletons +import Data.String.Conversions import Data.Text qualified as Text import Data.Text.Encoding qualified as T import Data.Text.Encoding qualified as Text diff --git a/services/gundeck/default.nix b/services/gundeck/default.nix index bf63e2899c8..a1c3759ede2 100644 --- a/services/gundeck/default.nix +++ b/services/gundeck/default.nix @@ -57,6 +57,7 @@ , safe-exceptions , scientific , servant-server +, string-conversions , tagged , tasty , tasty-ant-xml @@ -205,6 +206,7 @@ mkDerivation { quickcheck-instances quickcheck-state-machine scientific + string-conversions tasty tasty-hunit tasty-quickcheck diff --git a/services/gundeck/gundeck.cabal b/services/gundeck/gundeck.cabal index f5c42bf0ddf..45b786e9ca2 100644 --- a/services/gundeck/gundeck.cabal +++ b/services/gundeck/gundeck.cabal @@ -474,6 +474,7 @@ test-suite gundeck-tests , quickcheck-instances , quickcheck-state-machine , scientific + , string-conversions , tasty , tasty-hunit , tasty-quickcheck diff --git a/services/gundeck/src/Gundeck/Monad.hs b/services/gundeck/src/Gundeck/Monad.hs index 809c7192d1d..66b234569d3 100644 --- a/services/gundeck/src/Gundeck/Monad.hs +++ b/services/gundeck/src/Gundeck/Monad.hs @@ -187,7 +187,7 @@ lookupReqId :: Logger -> Request -> IO RequestId lookupReqId l r = case lookup requestIdName (requestHeaders r) of Just rid -> pure $ RequestId rid Nothing -> do - localRid <- RequestId . cs . UUID.toText <$> UUID.nextRandom + localRid <- RequestId . UUID.toASCIIBytes <$> UUID.nextRandom Log.info l $ "request-id" .= localRid ~~ "method" .= requestMethod r diff --git a/services/gundeck/src/Gundeck/Notification/Data.hs b/services/gundeck/src/Gundeck/Notification/Data.hs index d680e68f2c4..de18c7f5eaf 100644 --- a/services/gundeck/src/Gundeck/Notification/Data.hs +++ b/services/gundeck/src/Gundeck/Notification/Data.hs @@ -39,7 +39,7 @@ import Data.Sequence qualified as Seq import Gundeck.Env import Gundeck.Options (NotificationTTL (..), internalPageSize, maxPayloadLoadSize, settings) import Gundeck.Push.Native.Serialise () -import Imports hiding (cs) +import Imports import UnliftIO (pooledForConcurrentlyN_) import UnliftIO.Async (pooledMapConcurrentlyN) import Wire.API.Internal.Notification diff --git a/services/gundeck/src/Gundeck/Push.hs b/services/gundeck/src/Gundeck/Push.hs index 56ae375680e..3e6fa5c05c6 100644 --- a/services/gundeck/src/Gundeck/Push.hs +++ b/services/gundeck/src/Gundeck/Push.hs @@ -62,7 +62,7 @@ import Gundeck.ThreadBudget import Gundeck.Types import Gundeck.Types.Presence qualified as Presence import Gundeck.Util -import Imports hiding (cs) +import Imports import Network.HTTP.Types import Network.Wai.Utilities import System.Logger.Class (msg, val, (+++), (.=), (~~)) diff --git a/services/gundeck/src/Gundeck/Push/Websocket.hs b/services/gundeck/src/Gundeck/Push/Websocket.hs index c6a9190aba0..64a51c5f9d9 100644 --- a/services/gundeck/src/Gundeck/Push/Websocket.hs +++ b/services/gundeck/src/Gundeck/Push/Websocket.hs @@ -44,7 +44,7 @@ import Gundeck.Monad import Gundeck.Presence.Data qualified as Presence import Gundeck.Types.Presence import Gundeck.Util -import Imports hiding (cs) +import Imports import Network.HTTP.Client (HttpExceptionContent (..)) import Network.HTTP.Client.Internal qualified as Http import Network.HTTP.Types (StdMethod (POST), status200, status410) diff --git a/services/gundeck/src/Gundeck/Run.hs b/services/gundeck/src/Gundeck/Run.hs index 46d6b407c33..4a919bd0ba7 100644 --- a/services/gundeck/src/Gundeck/Run.hs +++ b/services/gundeck/src/Gundeck/Run.hs @@ -102,7 +102,7 @@ run o = do Just rid -> do mkapp (RequestId rid) req cont Nothing -> do - localRid <- RequestId . cs . UUID.toText <$> UUID.nextRandom + localRid <- RequestId . UUID.toASCIIBytes <$> UUID.nextRandom Log.info logger $ "request-id" .= localRid ~~ "method" .= Wai.requestMethod req diff --git a/services/gundeck/test/unit/MockGundeck.hs b/services/gundeck/test/unit/MockGundeck.hs index 0dacd4e378f..19d35241dbd 100644 --- a/services/gundeck/test/unit/MockGundeck.hs +++ b/services/gundeck/test/unit/MockGundeck.hs @@ -61,6 +61,7 @@ import Data.Misc (Milliseconds (Ms)) import Data.Range import Data.Scientific qualified as Scientific import Data.Set qualified as Set +import Data.String.Conversions import Gundeck.Aws.Arn as Aws import Gundeck.Options import Gundeck.Push diff --git a/services/gundeck/test/unit/ThreadBudget.hs b/services/gundeck/test/unit/ThreadBudget.hs index bd06c866dea..f9f21656aa3 100644 --- a/services/gundeck/test/unit/ThreadBudget.hs +++ b/services/gundeck/test/unit/ThreadBudget.hs @@ -30,6 +30,7 @@ import Control.Concurrent.Async import Control.Lens import Control.Monad.Catch (MonadCatch, catch) import Data.Metrics.Middleware (metrics) +import Data.String.Conversions import Data.Time import GHC.Generics import Gundeck.Options diff --git a/services/proxy/src/Proxy/Proxy.hs b/services/proxy/src/Proxy/Proxy.hs index 9cbb5d20899..cc7f6c5f8fc 100644 --- a/services/proxy/src/Proxy/Proxy.hs +++ b/services/proxy/src/Proxy/Proxy.hs @@ -17,11 +17,7 @@ -- You should have received a copy of the GNU Affero General Public License along -- with this program. If not, see . -module Proxy.Proxy - ( Proxy, - runProxy, - ) -where +module Proxy.Proxy (Proxy, runProxy) where import Bilge.Request (requestIdName) import Control.Lens hiding ((.=)) @@ -40,7 +36,7 @@ import System.Logger.Class hiding (Error, info) newtype Proxy a = Proxy { unProxy :: ReaderT Env IO a } - deriving + deriving newtype ( Functor, Applicative, Monad, @@ -68,7 +64,7 @@ lookupReqId :: Logger -> Request -> IO RequestId lookupReqId l r = case lookup requestIdName (requestHeaders r) of Just rid -> pure $ RequestId rid Nothing -> do - localRid <- RequestId . cs . UUID.toText <$> UUID.nextRandom + localRid <- RequestId . UUID.toASCIIBytes <$> UUID.nextRandom Log.info l $ "request-id" .= localRid ~~ "method" .= requestMethod r diff --git a/services/spar/default.nix b/services/spar/default.nix index f31e52c6ff1..ff861547cec 100644 --- a/services/spar/default.nix +++ b/services/spar/default.nix @@ -59,6 +59,7 @@ , servant-openapi3 , servant-server , silently +, string-conversions , tasty-hunit , text , text-latin1 @@ -67,6 +68,7 @@ , transformers , types-common , uri-bytestring +, utf8-string , uuid , vector , wai @@ -125,6 +127,7 @@ mkDerivation { transformers types-common uri-bytestring + utf8-string uuid wai wai-utilities @@ -179,6 +182,7 @@ mkDerivation { servant servant-server silently + string-conversions tasty-hunit text time @@ -186,6 +190,7 @@ mkDerivation { transformers types-common uri-bytestring + utf8-string uuid vector wai-extra @@ -220,6 +225,7 @@ mkDerivation { saml2-web-sso servant servant-openapi3 + string-conversions time tinylog types-common diff --git a/services/spar/migrate-data/src/Spar/DataMigration/V2_UserV2.hs b/services/spar/migrate-data/src/Spar/DataMigration/V2_UserV2.hs index ae532696d8d..ac7d49efca6 100644 --- a/services/spar/migrate-data/src/Spar/DataMigration/V2_UserV2.hs +++ b/services/spar/migrate-data/src/Spar/DataMigration/V2_UserV2.hs @@ -21,12 +21,14 @@ module Spar.DataMigration.V2_UserV2 (migration) where import Cassandra import qualified Conduit as C +import qualified Data.ByteString.UTF8 as UTF8 import Data.Conduit import qualified Data.Conduit.Combinators as CC import Data.Conduit.Internal (zipSources) import qualified Data.Conduit.List as CL import Data.Id import qualified Data.Map.Strict as Map +import qualified Data.Text as T import Data.Time (UTCTime) import Imports import qualified SAML2.WebSSO as SAML @@ -173,16 +175,16 @@ filterResolved resolver migMapInv = mbAssoc <- await for_ mbAssoc $ \(new@(issuer, nid), olds) -> do let yieldOld (nameId, uid) = yield (issuer, nid, nameId, uid) - let issuerURI = cs . serializeURIRef' . _fromIssuer $ issuer + let issuerURI = UTF8.toString . serializeURIRef' . _fromIssuer $ issuer case olds of [] -> pure () [old] -> yieldOld old (old1 : old2 : rest) -> lift (resolver new (List2 old1 old2 rest)) >>= \case Left _ -> - lift $ logError $ unwords ["Couldnt resolve collisision of", issuerURI, cs (unNormalizedUNameID nid), show olds] + lift $ logError $ unwords ["Couldnt resolve collisision of", issuerURI, T.unpack (unNormalizedUNameID nid), show olds] Right old -> do - lift $ logInfo $ unwords ["Resolved collision", issuerURI, cs (unNormalizedUNameID nid), show (fmap snd olds), "to", show (snd old)] + lift $ logInfo $ unwords ["Resolved collision", issuerURI, T.unpack (unNormalizedUNameID nid), show (fmap snd olds), "to", show (snd old)] yieldOld old go diff --git a/services/spar/spar.cabal b/services/spar/spar.cabal index 43e9582ceda..daa07906416 100644 --- a/services/spar/spar.cabal +++ b/services/spar/spar.cabal @@ -189,6 +189,7 @@ library , transformers , types-common , uri-bytestring + , utf8-string , uuid , wai , wai-utilities @@ -377,6 +378,7 @@ executable spar-integration , servant-server , silently , spar + , string-conversions , tasty-hunit , text , time @@ -472,6 +474,7 @@ executable spar-migrate-data , tinylog , types-common , uri-bytestring + , utf8-string default-language: Haskell2010 @@ -626,6 +629,7 @@ test-suite spec , servant , servant-openapi3 , spar + , string-conversions , time , tinylog , types-common diff --git a/services/spar/src/Spar/API.hs b/services/spar/src/Spar/API.hs index 8f27fab4dbc..ae3a3d94d90 100644 --- a/services/spar/src/Spar/API.hs +++ b/services/spar/src/Spar/API.hs @@ -55,7 +55,9 @@ import Data.Id import Data.Proxy import Data.Range import qualified Data.Set as Set +import Data.Text.Encoding.Error import qualified Data.Text.Lazy as T +import Data.Text.Lazy.Encoding import Data.Time import Imports import Polysemy @@ -357,7 +359,7 @@ idpGetRaw zusr idpid = do _ <- authorizeIdP zusr idp IdPRawMetadataStore.get idpid >>= \case Just txt -> pure $ RawIdPMetadata txt - Nothing -> throwSparSem $ SparIdPNotFound (cs $ show idpid) + Nothing -> throwSparSem $ SparIdPNotFound (T.pack $ show idpid) idpGetAll :: ( Member Random r, @@ -702,7 +704,10 @@ validateIdPUpdate zusr _idpMetadata _idpId = withDebugLog "validateIdPUpdate" (J where errUnknownIdP = SAML.UnknownIdP $ enc uri where - enc = cs . toLazyByteString . URI.serializeURIRef + enc = + decodeUtf8With lenientDecode + . toLazyByteString + . URI.serializeURIRef uri = _idpMetadata ^. SAML.edIssuer . SAML.fromIssuer withDebugLog :: Member (Logger String) r => String -> (a -> Maybe String) -> Sem r a -> Sem r a @@ -723,7 +728,11 @@ authorizeIdP :: Maybe UserId -> IdP -> Sem r (UserId, TeamId) -authorizeIdP Nothing _ = throw (SAML.CustomError $ SparNoPermission (cs $ show CreateUpdateDeleteIdp)) +authorizeIdP Nothing _ = + throw + ( SAML.CustomError $ + SparNoPermission (T.pack $ show CreateUpdateDeleteIdp) + ) authorizeIdP (Just zusr) idp = do let teamid = idp ^. SAML.idpExtraInfo . team GalleyAccess.assertHasPermission teamid CreateUpdateDeleteIdp zusr diff --git a/services/spar/src/Spar/App.hs b/services/spar/src/Spar/App.hs index eb51bd4232c..722b65ab91c 100644 --- a/services/spar/src/Spar/App.hs +++ b/services/spar/src/Spar/App.hs @@ -43,11 +43,17 @@ import Control.Lens hiding ((.=)) import Control.Monad.Except import Data.Aeson as Aeson (encode, object, (.=)) import Data.Aeson.Text as Aeson (encodeToLazyText) +import Data.ByteString (toStrict) import qualified Data.ByteString.Builder as Builder +import qualified Data.ByteString.UTF8 as UTF8 import qualified Data.CaseInsensitive as CI import Data.Id +import qualified Data.Text as Text import Data.Text.Ascii (encodeBase64, toText) +import qualified Data.Text.Encoding as Text +import Data.Text.Encoding.Error import qualified Data.Text.Lazy as LText +import qualified Data.Text.Lazy.Encoding as LText import Imports hiding (MonadReader, asks, log) import qualified Network.HTTP.Types.Status as Http import qualified Network.Wai.Utilities.Error as Wai @@ -182,7 +188,9 @@ createSamlUserWithId :: Role -> Sem r () createSamlUserWithId teamid buid suid role = do - uname <- either (throwSparSem . SparBadUserName . cs) pure $ Intra.mkUserName Nothing (UrefOnly suid) + uname <- + either (throwSparSem . SparBadUserName . LText.pack) pure $ + Intra.mkUserName Nothing (UrefOnly suid) buid' <- BrigAccess.createSAML suid buid teamid uname ManagedByWire Nothing Nothing Nothing role assert (buid == buid') $ pure () SAMLUserStore.insert suid buid @@ -212,7 +220,7 @@ autoprovisionSamlUser idp buid suid = do guardReplacedIdP :: Sem r () guardReplacedIdP = do unless (isNothing $ idp ^. idpExtraInfo . replacedBy) $ do - throwSparSem $ SparCannotCreateUsersOnReplacedIdP (cs . SAML.idPIdToST $ idp ^. idpId) + throwSparSem $ SparCannotCreateUsersOnReplacedIdP (LText.fromStrict . SAML.idPIdToST $ idp ^. idpId) -- IdPs in teams with scim tokens are not allowed to auto-provision. guardScimTokens :: Sem r () @@ -284,7 +292,7 @@ verdictHandler aresp verdict idp = do -- [...] If the containing message is in response to an , then -- the InResponseTo attribute MUST match the request's ID. Logger.log Logger.Debug $ "entering verdictHandler: " <> show (aresp, verdict) - reqid <- either (throwSparSem . SparNoRequestRefInResponse . cs) pure $ SAML.rspInResponseTo aresp + reqid <- either (throwSparSem . SparNoRequestRefInResponse . LText.pack) pure $ SAML.rspInResponseTo aresp format :: Maybe VerdictFormat <- VerdictFormatStore.get reqid resp <- case format of Just VerdictFormatWeb -> @@ -337,8 +345,17 @@ catchVerdictErrors = (`catch` hndlr) hndlr err = do waiErr <- renderSparErrorWithLogging err pure $ case waiErr of - Right (werr :: Wai.Error) -> VerifyHandlerError (cs $ Wai.label werr) (cs $ Wai.message werr) - Left (serr :: ServerError) -> VerifyHandlerError "unknown-error" (cs (errReasonPhrase serr) <> " " <> cs (errBody serr)) + Right (werr :: Wai.Error) -> + VerifyHandlerError + (LText.toStrict $ Wai.label werr) + (LText.toStrict $ Wai.message werr) + Left (serr :: ServerError) -> + VerifyHandlerError + "unknown-error" + ( Text.pack (errReasonPhrase serr) + <> " " + <> (Text.decodeUtf8With lenientDecode . toStrict . errBody $ serr) + ) -- | If a user attempts to login presenting a new IdP issuer, but there is no entry in -- @"spar.user"@ for her: lookup @"old_issuers"@ from @"spar.idp"@ for the new IdP, and @@ -397,7 +414,7 @@ verdictHandlerResultCore idp = \case SAML.AccessGranted uref -> do uid :: UserId <- do let team' = idp ^. idpExtraInfo . team - err = SparUserRefInNoOrMultipleTeams . cs . show $ uref + err = SparUserRefInNoOrMultipleTeams . LText.pack . show $ uref getUserByUrefUnsafe uref >>= \case Just usr -> do if userTeam usr == Just team' @@ -438,12 +455,12 @@ verdictHandlerWeb = forbiddenPage errlbl reasons = ServerError { errHTTPCode = 200, - errReasonPhrase = cs errlbl, -- (not sure what this is used for) + errReasonPhrase = Text.unpack errlbl, -- (not sure what this is used for) errBody = easyHtml $ "" <> " wire:sso:error:" - <> cs errlbl + <> LText.fromStrict errlbl <> "" <> "