Skip to content

Commit

Permalink
headerDecoder could use "time now" to ignore expired headers
Browse files Browse the repository at this point in the history
  • Loading branch information
choonkeat committed Sep 17, 2021
1 parent ebdf5fb commit 97fc97b
Show file tree
Hide file tree
Showing 4 changed files with 19 additions and 8 deletions.
6 changes: 3 additions & 3 deletions bin/elm-webapp

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion elm.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"name": "choonkeat/elm-webapp",
"summary": "Small framework for writing fullstack HTTP webapp in Elm. Try `npx elm-webapp`",
"license": "MIT",
"version": "2.0.0",
"version": "3.0.0",
"exposed-modules": [
"Webapp.Server.HTTP",
"Webapp.Server",
Expand Down
11 changes: 11 additions & 0 deletions src/Protocol/Auto.elm
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ module Protocol.Auto exposing (..)


import Protocol exposing (..)
import Array
import Dict
import Json.Decode
import Json.Encode
Expand Down Expand Up @@ -41,6 +42,11 @@ encodeList =
Json.Encode.list


encodeArrayArray : (a -> Json.Encode.Value) -> Array.Array a -> Json.Encode.Value
encodeArrayArray =
Json.Encode.array


encodeSetSet : (comparable -> Json.Encode.Value) -> Set.Set comparable -> Json.Encode.Value
encodeSetSet encoder =
Set.toList >> encodeList encoder
Expand Down Expand Up @@ -105,6 +111,11 @@ decodeList =
Json.Decode.list


decodeArrayArray : (Json.Decode.Decoder a) -> Json.Decode.Decoder (Array.Array a)
decodeArrayArray =
Json.Decode.array


decodeSetSet : (Json.Decode.Decoder comparable) -> Json.Decode.Decoder (Set.Set comparable)
decodeSetSet =
Json.Decode.list >> Json.Decode.map Set.fromList
Expand Down
8 changes: 4 additions & 4 deletions src/Webapp/Server.elm
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ type alias Ports msg x serverMsg =
-}
type alias Protocol msg x serverMsg clientMsg route header model =
{ headerDecoder : model -> Json.Decode.Decoder header
{ headerDecoder : Time.Posix -> model -> Json.Decode.Decoder header
, clientMsgDecoder : Json.Decode.Decoder clientMsg
, updateFromClient : header -> Time.Posix -> clientMsg -> model -> ( model, Task x serverMsg )
, serverMsgEncoder : serverMsg -> Json.Encode.Value
Expand Down Expand Up @@ -243,7 +243,7 @@ update appUpdate ports protocol msg model =

maybeHeader =
headersOf request
|> Json.Decode.decodeValue (protocol.headerDecoder model.appModel)
|> Json.Decode.decodeValue (protocol.headerDecoder now model.appModel)
|> Result.toMaybe

clientMsgResult =
Expand Down Expand Up @@ -324,14 +324,14 @@ routeWebsocketRequest :
Time.Posix
-> (header -> Time.Posix -> clientMsg -> model -> ( model, Task x serverMsg ))
-> Json.Decode.Decoder clientMsg
-> (model -> Json.Decode.Decoder header)
-> (Time.Posix -> model -> Json.Decode.Decoder header)
-> FrameworkModel model header
-> Webapp.Server.Websocket.WebsocketEvent
-> ( FrameworkModel model header, Cmd (FrameworkMsg msg x serverMsg) )
routeWebsocketRequest now updateFromClient clientMsgDecoder headerDecoder model event =
case event of
Webapp.Server.Websocket.Open conn key rawHeaders ->
case Json.Decode.decodeValue (headerDecoder model.appModel) rawHeaders of
case Json.Decode.decodeValue (headerDecoder now model.appModel) rawHeaders of
Ok headers ->
let
newWebsockets =
Expand Down

1 comment on commit 97fc97b

@choonkeat
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Background

headerDecoder is how applications can parse raw HTTP headers into a domain specific custom types that's easier to work with, e.g.

type RequestContext
    = LoggedIn User Permissions
    | Anonymous

Previously the headerDecoder type signature was

headerDecoder : serverState -> Json.Decode.Decoder header

Which allowed headerDecoder to use the information in the server state to determine how to decode the HTTP headers. e.g. we could use the serverState.signingSecret to verify that the signature of the JWT in Authorization header.

Problem

But headerDecoder would not have enough information to decide if the JWT is still valid or had expired.

Solution

Thus in this release, we changed to include the current time as first argument to headerDecoder

headerDecoder : Time.Posix -> serverState -> Json.Decode.Decoder header

Migration

Developers who continue to have no need for the current time in their headerDecoder, can update simply update the type signature and ignore the new parameter

- headerDecoder : ServerState -> Json.Decode.Decoder Types.RequestContext
- headerDecoder serverState =
+ headerDecoder : Time.Posix -> ServerState -> Json.Decode.Decoder Types.RequestContext
+ headerDecoder _ serverState =

Please sign in to comment.