@@ -13,6 +13,7 @@ import Control.Monad.Reader
13
13
import Data.Binary.Builder qualified as Builder
14
14
import Data.ByteString.Char8 qualified as BSC
15
15
import Data.ByteString.Lazy.Char8 qualified as BL
16
+ import Data.List.Extra qualified as List
16
17
import Data.Map qualified as Map
17
18
import Data.Maybe qualified as Maybe
18
19
import Data.Text qualified as Text
@@ -21,6 +22,18 @@ import Data.Time (NominalDiffTime, diffUTCTime, getCurrentTime)
21
22
import Data.Typeable qualified as Typeable
22
23
import Data.UUID (UUID )
23
24
import Data.Vault.Lazy as Vault
25
+ import Network.HTTP.Types (HeaderName , statusCode )
26
+ import Network.HTTP.Types qualified as HTTP
27
+ import Network.URI qualified as URI
28
+ import Network.Wai
29
+ import Network.Wai qualified as Wai
30
+ import Network.Wai.Handler.Warp (run )
31
+ import Network.Wai.Internal qualified as Wai
32
+ import Network.Wai.Middleware.Cors
33
+ import Network.Wai.Middleware.Gzip qualified as Gzip
34
+ import Network.Wai.Middleware.RequestLogger (logStdoutDev )
35
+ import Network.Wai.Middleware.Routed (routedMiddleware )
36
+ import Servant
24
37
import Share.App
25
38
import Share.Env qualified as Env
26
39
import Share.IDs (RequestId , UserId )
@@ -41,17 +54,6 @@ import Share.Web.App (WebApp, localRequestCtx)
41
54
import Share.Web.App qualified as WebApp
42
55
import Share.Web.Errors
43
56
import Share.Web.Impl qualified as Web
44
- import Network.HTTP.Types (HeaderName , statusCode )
45
- import Network.HTTP.Types qualified as HTTP
46
- import Network.Wai
47
- import Network.Wai qualified as Wai
48
- import Network.Wai.Handler.Warp (run )
49
- import Network.Wai.Internal qualified as Wai
50
- import Network.Wai.Middleware.Cors
51
- import Network.Wai.Middleware.Gzip qualified as Gzip
52
- import Network.Wai.Middleware.RequestLogger (logStdoutDev )
53
- import Network.Wai.Middleware.Routed (routedMiddleware )
54
- import Servant
55
57
import System.Log.FastLogger (FastLogger , FormattedTime , LogStr )
56
58
import System.Log.Raven qualified as Sentry
57
59
import System.Log.Raven.Types qualified as Sentry
@@ -216,15 +218,34 @@ mkApp env = do
216
218
(" search" : _) -> True
217
219
(" sync" : _) -> True
218
220
_ -> False
219
- corsPolicy :: CorsResourcePolicy
220
- corsPolicy =
221
- simpleCorsResourcePolicy
222
- { corsOrigins = Just ([BSC. pack . show @ URI $ Env. shareUiOrigin env, BSC. pack . show @ URI $ Env. cloudUiOrigin env], True {- allow receiving cookies in requests made from these origins -} ),
223
- corsRequestHeaders = " X-XSRF-TOKEN" : simpleHeaders,
224
- corsMethods = [" PATCH" , " DELETE" , " PUT" ] <> simpleMethods
225
- }
221
+ corsPolicy :: Request -> Maybe CorsResourcePolicy
222
+ corsPolicy req = case Deployment. deployment of
223
+ Deployment. Local -> Nothing
224
+ Deployment. Staging ->
225
+ case (List. lookup " Origin" $ requestHeaders req) >>= URI. parseAbsoluteURI . BSC. unpack of
226
+ Just uri
227
+ | isValidSubdomain uri ->
228
+ let rootSubdomain = uri {uriPath = [] , uriQuery = [] , uriFragment = [] }
229
+ in -- Allow requests from any subdomain of the share staging origin.
230
+ Just $ defaultCorsPolicy [BSC. pack . show @ URI $ rootSubdomain]
231
+ _ -> Just $ defaultCorsPolicy []
232
+ Deployment. Production ->
233
+ Just $ defaultCorsPolicy []
234
+ where
235
+ isValidSubdomain origin = fromMaybe False $ do
236
+ originHostParts <- List. splitOn " ." . URI. uriRegName <$> URI. uriAuthority origin
237
+ shareHostParts <- List. splitOn " ." . URI. uriRegName <$> URI. uriAuthority (Env. shareUiOrigin env)
238
+ cloudHostParts <- List. splitOn " ." . URI. uriRegName <$> URI. uriAuthority (Env. cloudUiOrigin env)
239
+ pure $ shareHostParts `List.isSuffixOf` originHostParts || cloudHostParts `List.isSuffixOf` originHostParts
240
+ -- Require that the request come from one of the known cloud or share origins.
241
+ defaultCorsPolicy additionalOrigins =
242
+ simpleCorsResourcePolicy
243
+ { corsOrigins = Just ([BSC. pack . show @ URI $ Env. shareUiOrigin env, BSC. pack . show @ URI $ Env. cloudUiOrigin env] <> additionalOrigins, True {- allow receiving cookies in requests made from these origins -} ),
244
+ corsRequestHeaders = " X-XSRF-TOKEN" : simpleHeaders,
245
+ corsMethods = [" PATCH" , " DELETE" , " PUT" ] <> simpleMethods
246
+ }
226
247
corsMiddleware :: Middleware
227
- corsMiddleware = cors ( const $ Just corsPolicy)
248
+ corsMiddleware = cors corsPolicy
228
249
229
250
mkReqLogger :: Vault. Key WebApp. ReqTagsVar -> IO FormattedTime -> FastLogger -> Middleware
230
251
mkReqLogger reqTagsKey timeCache logger app = do
0 commit comments