Skip to content

Commit c161ac5

Browse files
authored
Merge pull request #12 from unisoncomputing/cp/relax-staging-cors
Allow staging deploy previews in cors
2 parents 899060e + 66226dc commit c161ac5

File tree

1 file changed

+40
-19
lines changed

1 file changed

+40
-19
lines changed

src/Share.hs

Lines changed: 40 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import Control.Monad.Reader
1313
import Data.Binary.Builder qualified as Builder
1414
import Data.ByteString.Char8 qualified as BSC
1515
import Data.ByteString.Lazy.Char8 qualified as BL
16+
import Data.List.Extra qualified as List
1617
import Data.Map qualified as Map
1718
import Data.Maybe qualified as Maybe
1819
import Data.Text qualified as Text
@@ -21,6 +22,18 @@ import Data.Time (NominalDiffTime, diffUTCTime, getCurrentTime)
2122
import Data.Typeable qualified as Typeable
2223
import Data.UUID (UUID)
2324
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
2437
import Share.App
2538
import Share.Env qualified as Env
2639
import Share.IDs (RequestId, UserId)
@@ -41,17 +54,6 @@ import Share.Web.App (WebApp, localRequestCtx)
4154
import Share.Web.App qualified as WebApp
4255
import Share.Web.Errors
4356
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
5557
import System.Log.FastLogger (FastLogger, FormattedTime, LogStr)
5658
import System.Log.Raven qualified as Sentry
5759
import System.Log.Raven.Types qualified as Sentry
@@ -216,15 +218,34 @@ mkApp env = do
216218
("search" : _) -> True
217219
("sync" : _) -> True
218220
_ -> 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+
}
226247
corsMiddleware :: Middleware
227-
corsMiddleware = cors (const $ Just corsPolicy)
248+
corsMiddleware = cors corsPolicy
228249

229250
mkReqLogger :: Vault.Key WebApp.ReqTagsVar -> IO FormattedTime -> FastLogger -> Middleware
230251
mkReqLogger reqTagsKey timeCache logger app = do

0 commit comments

Comments
 (0)