mirror of
https://github.com/TheAnachronism/docspell.git
synced 2025-06-22 10:28:27 +00:00
Add OpenID support to webapp
This commit is contained in:
@ -87,6 +87,7 @@ module Api exposing
|
||||
, mergeItems
|
||||
, moveAttachmentBefore
|
||||
, newInvite
|
||||
, openIdAuthLink
|
||||
, postCustomField
|
||||
, postEquipment
|
||||
, postNewUser
|
||||
@ -935,6 +936,11 @@ newInvite flags req receive =
|
||||
--- Login
|
||||
|
||||
|
||||
openIdAuthLink : Flags -> String -> String
|
||||
openIdAuthLink flags provider =
|
||||
flags.config.baseUrl ++ "/api/v1/open/auth/openid/" ++ provider
|
||||
|
||||
|
||||
login : Flags -> UserPass -> (Result Http.Error AuthResult -> msg) -> Cmd msg
|
||||
login flags up receive =
|
||||
Http.post
|
||||
|
@ -82,6 +82,12 @@ init key url flags_ settings =
|
||||
( csm, csc ) =
|
||||
Page.CollectiveSettings.Data.init flags
|
||||
|
||||
( loginm, loginc ) =
|
||||
Page.Login.Data.init flags
|
||||
(Page.loginPageReferrer page
|
||||
|> Tuple.second
|
||||
)
|
||||
|
||||
homeViewMode =
|
||||
if settings.searchMenuVisible then
|
||||
Page.Home.Data.SearchView
|
||||
@ -94,7 +100,7 @@ init key url flags_ settings =
|
||||
, page = page
|
||||
, version = Api.Model.VersionInfo.empty
|
||||
, homeModel = Page.Home.Data.init flags homeViewMode
|
||||
, loginModel = Page.Login.Data.emptyModel
|
||||
, loginModel = loginm
|
||||
, manageDataModel = mdm
|
||||
, collSettingsModel = csm
|
||||
, userSettingsModel = um
|
||||
@ -116,6 +122,7 @@ init key url flags_ settings =
|
||||
[ Cmd.map UserSettingsMsg uc
|
||||
, Cmd.map ManageDataMsg mdc
|
||||
, Cmd.map CollSettingsMsg csc
|
||||
, Cmd.map LoginMsg loginc
|
||||
]
|
||||
)
|
||||
|
||||
|
@ -158,7 +158,7 @@ updateWithSub msg model =
|
||||
|
||||
LogoutResp _ ->
|
||||
( { model | loginModel = Page.Login.Data.emptyModel }
|
||||
, Page.goto (LoginPage Nothing)
|
||||
, Page.goto (LoginPage ( Nothing, False ))
|
||||
, Sub.none
|
||||
)
|
||||
|
||||
@ -216,20 +216,24 @@ updateWithSub msg model =
|
||||
NavRequest req ->
|
||||
case req of
|
||||
Internal url ->
|
||||
let
|
||||
isCurrent =
|
||||
Page.fromUrl url
|
||||
|> Maybe.map (\p -> p == model.page)
|
||||
|> Maybe.withDefault True
|
||||
in
|
||||
( model
|
||||
, if isCurrent then
|
||||
Cmd.none
|
||||
if String.startsWith "/app" url.path then
|
||||
let
|
||||
isCurrent =
|
||||
Page.fromUrl url
|
||||
|> Maybe.map (\p -> p == model.page)
|
||||
|> Maybe.withDefault True
|
||||
in
|
||||
( model
|
||||
, if isCurrent then
|
||||
Cmd.none
|
||||
|
||||
else
|
||||
Nav.pushUrl model.key (Url.toString url)
|
||||
, Sub.none
|
||||
)
|
||||
else
|
||||
Nav.pushUrl model.key (Url.toString url)
|
||||
, Sub.none
|
||||
)
|
||||
|
||||
else
|
||||
( model, Nav.load <| Url.toString url, Sub.none )
|
||||
|
||||
External url ->
|
||||
( model
|
||||
|
@ -17,6 +17,12 @@ module Data.Flags exposing
|
||||
import Api.Model.AuthResult exposing (AuthResult)
|
||||
|
||||
|
||||
type alias OpenIdAuth =
|
||||
{ provider : String
|
||||
, name : String
|
||||
}
|
||||
|
||||
|
||||
type alias Config =
|
||||
{ appName : String
|
||||
, baseUrl : String
|
||||
@ -27,6 +33,7 @@ type alias Config =
|
||||
, maxPageSize : Int
|
||||
, maxNoteLength : Int
|
||||
, showClassificationSettings : Bool
|
||||
, openIdAuth : List OpenIdAuth
|
||||
}
|
||||
|
||||
|
||||
|
@ -26,6 +26,7 @@ gb err =
|
||||
, invalidInput = "Invalid input when processing the request."
|
||||
, notFound = "The requested resource doesn't exist."
|
||||
, invalidBody = \str -> "There was an error decoding the response: " ++ str
|
||||
, accessDenied = "Access denied"
|
||||
}
|
||||
in
|
||||
errorToString texts err
|
||||
@ -44,6 +45,7 @@ de err =
|
||||
, invalidInput = "Die Daten im Request waren ungültig."
|
||||
, notFound = "Die angegebene Ressource wurde nicht gefunden."
|
||||
, invalidBody = \str -> "Es gab einen Fehler beim Dekodieren der Antwort: " ++ str
|
||||
, accessDenied = "Zugriff verweigert"
|
||||
}
|
||||
in
|
||||
errorToString texts err
|
||||
@ -61,6 +63,7 @@ type alias Texts =
|
||||
, invalidInput : String
|
||||
, notFound : String
|
||||
, invalidBody : String -> String
|
||||
, accessDenied : String
|
||||
}
|
||||
|
||||
|
||||
@ -90,6 +93,9 @@ errorToString texts error =
|
||||
if sc == 404 then
|
||||
texts.notFound
|
||||
|
||||
else if sc == 403 then
|
||||
texts.accessDenied
|
||||
|
||||
else if sc >= 400 && sc < 500 then
|
||||
texts.invalidInput
|
||||
|
||||
|
@ -29,6 +29,7 @@ type alias Texts =
|
||||
, noAccount : String
|
||||
, signupLink : String
|
||||
, otpCode : String
|
||||
, or : String
|
||||
}
|
||||
|
||||
|
||||
@ -47,6 +48,7 @@ gb =
|
||||
, noAccount = "No account?"
|
||||
, signupLink = "Sign up!"
|
||||
, otpCode = "Authentication code"
|
||||
, or = "Or"
|
||||
}
|
||||
|
||||
|
||||
@ -65,4 +67,5 @@ de =
|
||||
, noAccount = "Kein Konto?"
|
||||
, signupLink = "Hier registrieren!"
|
||||
, otpCode = "Authentifizierungscode"
|
||||
, or = "Oder"
|
||||
}
|
||||
|
@ -33,7 +33,7 @@ import Util.Maybe
|
||||
|
||||
type Page
|
||||
= HomePage
|
||||
| LoginPage (Maybe Page)
|
||||
| LoginPage ( Maybe Page, Bool )
|
||||
| ManageDataPage
|
||||
| CollectiveSettingPage
|
||||
| UserSettingPage
|
||||
@ -99,10 +99,10 @@ loginPage : Page -> Page
|
||||
loginPage p =
|
||||
case p of
|
||||
LoginPage _ ->
|
||||
LoginPage Nothing
|
||||
LoginPage ( Nothing, False )
|
||||
|
||||
_ ->
|
||||
LoginPage (Just p)
|
||||
LoginPage ( Just p, False )
|
||||
|
||||
|
||||
pageName : Page -> String
|
||||
@ -144,14 +144,14 @@ pageName page =
|
||||
"Item"
|
||||
|
||||
|
||||
loginPageReferrer : Page -> Maybe Page
|
||||
loginPageReferrer : Page -> ( Maybe Page, Bool )
|
||||
loginPageReferrer page =
|
||||
case page of
|
||||
LoginPage r ->
|
||||
r
|
||||
LoginPage ( r, flag ) ->
|
||||
( r, flag )
|
||||
|
||||
_ ->
|
||||
Nothing
|
||||
( Nothing, False )
|
||||
|
||||
|
||||
uploadId : Page -> Maybe String
|
||||
@ -170,7 +170,7 @@ pageToString page =
|
||||
HomePage ->
|
||||
"/app/home"
|
||||
|
||||
LoginPage referer ->
|
||||
LoginPage ( referer, _ ) ->
|
||||
case referer of
|
||||
Just (LoginPage _) ->
|
||||
"/app/login"
|
||||
@ -253,7 +253,7 @@ parser =
|
||||
, s pathPrefix </> s "home"
|
||||
]
|
||||
)
|
||||
, Parser.map LoginPage (s pathPrefix </> s "login" <?> pageQuery)
|
||||
, Parser.map LoginPage (s pathPrefix </> s "login" <?> loginPageParser)
|
||||
, Parser.map ManageDataPage (s pathPrefix </> s "managedata")
|
||||
, Parser.map CollectiveSettingPage (s pathPrefix </> s "csettings")
|
||||
, Parser.map UserSettingPage (s pathPrefix </> s "usettings")
|
||||
@ -280,6 +280,16 @@ fromString str =
|
||||
fromUrl url
|
||||
|
||||
|
||||
loginPageOAuthQuery : Query.Parser Bool
|
||||
loginPageOAuthQuery =
|
||||
Query.map Util.Maybe.nonEmpty (Query.string "openid")
|
||||
|
||||
|
||||
loginPageParser : Query.Parser ( Maybe Page, Bool )
|
||||
loginPageParser =
|
||||
Query.map2 Tuple.pair pageQuery loginPageOAuthQuery
|
||||
|
||||
|
||||
pageQuery : Query.Parser (Maybe Page)
|
||||
pageQuery =
|
||||
let
|
||||
|
@ -11,9 +11,12 @@ module Page.Login.Data exposing
|
||||
, Model
|
||||
, Msg(..)
|
||||
, emptyModel
|
||||
, init
|
||||
)
|
||||
|
||||
import Api
|
||||
import Api.Model.AuthResult exposing (AuthResult)
|
||||
import Data.Flags exposing (Flags)
|
||||
import Http
|
||||
import Page exposing (Page(..))
|
||||
|
||||
@ -51,6 +54,19 @@ emptyModel =
|
||||
}
|
||||
|
||||
|
||||
init : Flags -> Bool -> ( Model, Cmd Msg )
|
||||
init flags oauth =
|
||||
let
|
||||
cmd =
|
||||
if oauth then
|
||||
Api.loginSession flags AuthResp
|
||||
|
||||
else
|
||||
Cmd.none
|
||||
in
|
||||
( emptyModel, cmd )
|
||||
|
||||
|
||||
type Msg
|
||||
= SetUsername String
|
||||
| SetPassword String
|
||||
|
@ -15,8 +15,8 @@ import Page.Login.Data exposing (..)
|
||||
import Ports
|
||||
|
||||
|
||||
update : Maybe Page -> Flags -> Msg -> Model -> ( Model, Cmd Msg, Maybe AuthResult )
|
||||
update referrer flags msg model =
|
||||
update : ( Maybe Page, Bool ) -> Flags -> Msg -> Model -> ( Model, Cmd Msg, Maybe AuthResult )
|
||||
update ( referrer, oauth ) flags msg model =
|
||||
case msg of
|
||||
SetUsername str ->
|
||||
( { model | username = str }, Cmd.none, Nothing )
|
||||
|
@ -7,8 +7,10 @@
|
||||
|
||||
module Page.Login.View2 exposing (viewContent, viewSidebar)
|
||||
|
||||
import Api
|
||||
import Api.Model.AuthResult exposing (AuthResult)
|
||||
import Api.Model.VersionInfo exposing (VersionInfo)
|
||||
import Comp.Basic as B
|
||||
import Data.Flags exposing (Flags)
|
||||
import Data.UiSettings exposing (UiSettings)
|
||||
import Html exposing (..)
|
||||
@ -53,6 +55,7 @@ viewContent texts flags versionInfo _ model =
|
||||
|
||||
StepLogin ->
|
||||
loginForm texts flags model
|
||||
, openIdLinks texts flags
|
||||
]
|
||||
, a
|
||||
[ class "inline-flex items-center mt-4 text-xs opacity-50 hover:opacity-90"
|
||||
@ -72,6 +75,35 @@ viewContent texts flags versionInfo _ model =
|
||||
]
|
||||
|
||||
|
||||
openIdLinks : Texts -> Flags -> Html Msg
|
||||
openIdLinks texts flags =
|
||||
let
|
||||
renderLink prov =
|
||||
a
|
||||
[ href (Api.openIdAuthLink flags prov.provider)
|
||||
, class S.link
|
||||
]
|
||||
[ i [ class "fab fa-openid mr-1" ] []
|
||||
, text prov.name
|
||||
]
|
||||
in
|
||||
case flags.config.openIdAuth of
|
||||
[] ->
|
||||
span [ class "hidden" ] []
|
||||
|
||||
provs ->
|
||||
div [ class "mt-3" ]
|
||||
[ B.horizontalDivider
|
||||
{ label = texts.or
|
||||
, topCss = "w-2/3 mb-4 hidden md:inline-flex w-full"
|
||||
, labelCss = "px-4 bg-gray-200 bg-opacity-50"
|
||||
, lineColor = "bg-gray-300 dark:bg-bluegray-600"
|
||||
}
|
||||
, div [ class "flex flex-row space-x-4 items-center justify-center" ]
|
||||
(List.map renderLink provs)
|
||||
]
|
||||
|
||||
|
||||
otpForm : Texts -> Flags -> Model -> AuthResult -> Html Msg
|
||||
otpForm texts flags model acc =
|
||||
Html.form
|
||||
|
@ -97,7 +97,7 @@ update flags msg model =
|
||||
|
||||
cmd =
|
||||
if r.success then
|
||||
Page.goto (LoginPage Nothing)
|
||||
Page.goto (LoginPage ( Nothing, False ))
|
||||
|
||||
else
|
||||
Cmd.none
|
||||
|
@ -232,7 +232,7 @@ viewContent texts flags _ model =
|
||||
[ text texts.alreadySignedUp
|
||||
]
|
||||
, a
|
||||
[ Page.href (LoginPage Nothing)
|
||||
[ Page.href (LoginPage ( Nothing, False ))
|
||||
, class ("ml-2" ++ S.link)
|
||||
]
|
||||
[ i [ class "fa fa-user-plus mr-1" ] []
|
||||
|
Reference in New Issue
Block a user