{-# LANGUAGE OverloadedStrings #-}

-- This file is part of the Wire Server implementation.
--
-- Copyright (C) 2025 Wire Swiss GmbH <opensource@wire.com>
--
-- This program is free software: you can redistribute it and/or modify it under
-- the terms of the GNU Affero General Public License as published by the Free
-- Software Foundation, either version 3 of the License, or (at your option) any
-- later version.
--
-- This program is distributed in the hope that it will be useful, but WITHOUT
-- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
-- FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
-- details.
--
-- You should have received a copy of the GNU Affero General Public License along
-- with this program. If not, see <https://www.gnu.org/licenses/>.

module SAML2.WebSSO.Error where

import Data.String.Conversions
import Data.Void (Void, absurd)
import Servant.Server

data Error err
  = UnknownIdP LT
  | Forbidden LT
  | BadSamlResponseBase64Error LT
  | BadSamlResponseXmlError LT
  | BadSamlResponseSamlError LT
  | BadSamlResponseFormFieldMissing
  | BadSamlResponseIssuerMissing
  | BadSamlResponseInconsistentIdPIssuerInfo
  | BadSamlResponseNoAssertions
  | BadSamlResponseAssertionWithoutID
  | BadSamlResponseInvalidSignature LT
  | BadServerConfig LT
  | InvalidCert LT
  | UnknownError
  | CustomServant ServerError
  | CustomError err
  deriving (Eq, Show)

type SimpleError = Error Void

toServerError :: SimpleError -> ServerError
toServerError (UnknownIdP msg) = err404 {errBody = "Unknown IdP: " <> cs msg}
toServerError (Forbidden msg) = err403 {errBody = cs msg}
-- (this should probably be 401, not 403, but according to the standard we would also need to add
-- a WWW-Authenticate header if we do that, and we are not using saml, not basic auth.
-- https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#4xx_Client_errors)
toServerError (BadSamlResponseBase64Error msg) = err400 {errBody = "Bad response: base64 error: " <> cs msg}
toServerError (BadSamlResponseXmlError msg) = err400 {errBody = "Bad response: xml parse error: " <> cs msg}
toServerError (BadSamlResponseSamlError msg) = err400 {errBody = "Bad response: saml parse error: " <> cs msg}
toServerError BadSamlResponseFormFieldMissing = err400 {errBody = "Bad response: SAMLResponse form field missing from HTTP body"}
toServerError BadSamlResponseIssuerMissing = err400 {errBody = "Bad response: no Issuer in AuthnResponse"}
toServerError BadSamlResponseInconsistentIdPIssuerInfo = err403 {errBody = "Bad response: Inconsistent IdP Issuers (must be exactly one in the IdP response)"}
toServerError BadSamlResponseNoAssertions = err400 {errBody = "Bad response: no assertions in AuthnResponse"}
toServerError BadSamlResponseAssertionWithoutID = err400 {errBody = "Bad response: assertion without ID"}
toServerError (BadSamlResponseInvalidSignature msg) = err400 {errBody = cs msg}
toServerError (InvalidCert msg) = err400 {errBody = "Invalid certificate: " <> cs msg}
toServerError (BadServerConfig msg) = err400 {errBody = "Invalid server config: " <> cs msg}
toServerError UnknownError = err500 {errBody = "Internal server error.  Please consult the logs."}
toServerError (CustomServant err) = err
toServerError (CustomError avoid) = absurd avoid
