commit
acd4a07d5e
|
@ -4,3 +4,7 @@ elm-stuff
|
|||
repl-temp-*
|
||||
# VScode settings
|
||||
.vscode/
|
||||
|
||||
# Elm output
|
||||
index.html
|
||||
elm.js
|
||||
|
|
|
@ -190,6 +190,7 @@ loginWithUsernameAndPasswordV1 { username, password } =
|
|||
, refresh = out.refreshToken
|
||||
, value = out.accessToken
|
||||
}
|
||||
, E.RemovePasswordIfNecessary
|
||||
, out.user
|
||||
|> Maybe.map (V.SetUser >> E.ContentUpdate)
|
||||
|> E.Optional
|
||||
|
@ -231,6 +232,7 @@ loginWithUsernameAndPasswordV2 { deviceId, initialDeviceDisplayName, username, p
|
|||
, refresh = Nothing
|
||||
, value = out.accessToken
|
||||
}
|
||||
, E.RemovePasswordIfNecessary
|
||||
, out.user
|
||||
|> Maybe.map (V.SetUser >> E.ContentUpdate)
|
||||
|> E.Optional
|
||||
|
@ -282,6 +284,7 @@ loginWithUsernameAndPasswordV3 { deviceId, initialDeviceDisplayName, username, p
|
|||
, refresh = Nothing
|
||||
, value = out.accessToken
|
||||
}
|
||||
, E.RemovePasswordIfNecessary
|
||||
, out.user
|
||||
|> Maybe.map (V.SetUser >> E.ContentUpdate)
|
||||
|> E.Optional
|
||||
|
@ -333,6 +336,7 @@ loginWithUsernameAndPasswordV4 { deviceId, initialDeviceDisplayName, username, p
|
|||
, refresh = Nothing
|
||||
, value = out.accessToken
|
||||
}
|
||||
, E.RemovePasswordIfNecessary
|
||||
, out.user
|
||||
|> Maybe.map (V.SetUser >> E.ContentUpdate)
|
||||
|> E.Optional
|
||||
|
@ -388,6 +392,7 @@ loginWithUsernameAndPasswordV5 { deviceId, initialDeviceDisplayName, username, p
|
|||
, refresh = Nothing
|
||||
, value = out.accessToken
|
||||
}
|
||||
, E.RemovePasswordIfNecessary
|
||||
, out.user
|
||||
|> Maybe.map (V.SetUser >> E.ContentUpdate)
|
||||
|> E.Optional
|
||||
|
@ -444,6 +449,7 @@ loginWithUsernameAndPasswordV6 { deviceId, enableRefreshToken, initialDeviceDisp
|
|||
, refresh = out.refreshToken
|
||||
, value = out.accessToken
|
||||
}
|
||||
, E.RemovePasswordIfNecessary
|
||||
, out.user
|
||||
|> Maybe.map (V.SetUser >> E.ContentUpdate)
|
||||
|> E.Optional
|
||||
|
@ -500,6 +506,7 @@ loginWithUsernameAndPasswordV7 { deviceId, enableRefreshToken, initialDeviceDisp
|
|||
, refresh = out.refreshToken
|
||||
, value = out.accessToken
|
||||
}
|
||||
, E.RemovePasswordIfNecessary
|
||||
, E.ContentUpdate (V.SetUser out.user)
|
||||
, out.wellKnown
|
||||
|> Maybe.map (.homeserver >> .baseUrl)
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
module Internal.Config.Default exposing
|
||||
( currentVersion, deviceName
|
||||
, syncTime
|
||||
, removePasswordOnLogin
|
||||
)
|
||||
|
||||
{-| This module hosts all default settings and configurations that the Vault
|
||||
|
@ -16,6 +17,11 @@ will assume until overriden by the user.
|
|||
|
||||
@docs syncTime
|
||||
|
||||
|
||||
## Security
|
||||
|
||||
@docs removePasswordOnLogin
|
||||
|
||||
-}
|
||||
|
||||
|
||||
|
@ -52,3 +58,13 @@ The value is in miliseconds, so it is set at 30,000.
|
|||
syncTime : Int
|
||||
syncTime =
|
||||
30 * 1000
|
||||
|
||||
|
||||
{-| Once the Matrix API has logged in successfully, it does not need to remember
|
||||
the user's password. However, to keep the Vault logged in automatically, one may
|
||||
choose to remember the password in order to get a new access token when an old
|
||||
access token has expired.
|
||||
-}
|
||||
removePasswordOnLogin : Bool
|
||||
removePasswordOnLogin =
|
||||
True
|
||||
|
|
|
@ -321,6 +321,7 @@ fields :
|
|||
, settings :
|
||||
{ currentVersion : Desc
|
||||
, deviceName : Desc
|
||||
, removePasswordOnLogin : Desc
|
||||
, syncTime : Desc
|
||||
}
|
||||
, timeline :
|
||||
|
@ -501,6 +502,9 @@ fields =
|
|||
, deviceName =
|
||||
[ "Indicates the device name that is communicated to the Matrix API."
|
||||
]
|
||||
, removePasswordOnLogin =
|
||||
[ "Remove the password as soon as a valid access token has been received."
|
||||
]
|
||||
, syncTime =
|
||||
[ "Indicates the frequency in miliseconds with which the Elm SDK should long-poll the /sync endpoint."
|
||||
]
|
||||
|
|
|
@ -78,6 +78,7 @@ type EnvelopeUpdate a
|
|||
| More (List (EnvelopeUpdate a))
|
||||
| Optional (Maybe (EnvelopeUpdate a))
|
||||
| RemoveAccessToken String
|
||||
| RemovePasswordIfNecessary
|
||||
| SetAccessToken AccessToken
|
||||
| SetBaseUrl String
|
||||
| SetDeviceId String
|
||||
|
@ -311,6 +312,13 @@ update updateContent eu ({ context } as data) =
|
|||
RemoveAccessToken token ->
|
||||
{ data | context = { context | accessTokens = Hashdict.removeKey token context.accessTokens } }
|
||||
|
||||
RemovePasswordIfNecessary ->
|
||||
if data.settings.removePasswordOnLogin then
|
||||
{ data | context = { context | password = Nothing } }
|
||||
|
||||
else
|
||||
data
|
||||
|
||||
SetAccessToken a ->
|
||||
{ data | context = { context | accessTokens = Hashdict.insert a context.accessTokens } }
|
||||
|
||||
|
|
|
@ -35,6 +35,7 @@ behave under the user's preferred settings.
|
|||
type alias Settings =
|
||||
{ currentVersion : String
|
||||
, deviceName : String
|
||||
, removePasswordOnLogin : Bool
|
||||
, syncTime : Int
|
||||
}
|
||||
|
||||
|
@ -43,7 +44,7 @@ type alias Settings =
|
|||
-}
|
||||
coder : Json.Coder Settings
|
||||
coder =
|
||||
Json.object3
|
||||
Json.object4
|
||||
{ name = Text.docs.settings.name
|
||||
, description = Text.docs.settings.description
|
||||
, init = Settings
|
||||
|
@ -66,6 +67,21 @@ coder =
|
|||
, defaultToString = identity
|
||||
}
|
||||
)
|
||||
(Json.field.optional.withDefault
|
||||
{ fieldName = "removePasswordOnLogin"
|
||||
, toField = .removePasswordOnLogin
|
||||
, description = Text.fields.settings.removePasswordOnLogin
|
||||
, coder = Json.bool
|
||||
, default = Tuple.pair Default.removePasswordOnLogin []
|
||||
, defaultToString =
|
||||
\b ->
|
||||
if b then
|
||||
"true"
|
||||
|
||||
else
|
||||
"false"
|
||||
}
|
||||
)
|
||||
(Json.field.optional.withDefault
|
||||
{ fieldName = "syncTime"
|
||||
, toField = .syncTime
|
||||
|
@ -97,5 +113,6 @@ init : Settings
|
|||
init =
|
||||
{ currentVersion = Default.currentVersion
|
||||
, deviceName = Default.deviceName
|
||||
, removePasswordOnLogin = Default.removePasswordOnLogin
|
||||
, syncTime = Default.syncTime
|
||||
}
|
||||
|
|
|
@ -45,7 +45,7 @@ import Internal.Values.User as User exposing (User)
|
|||
type alias Vault =
|
||||
{ accountData : Dict String Json.Value
|
||||
, rooms : Hashdict Room
|
||||
, user : User
|
||||
, user : Maybe User
|
||||
}
|
||||
|
||||
|
||||
|
@ -81,7 +81,7 @@ coder =
|
|||
, coder = Hashdict.coder .roomId Room.coder
|
||||
}
|
||||
)
|
||||
(Json.field.required
|
||||
(Json.field.optional.value
|
||||
{ fieldName = "user"
|
||||
, toField = .user
|
||||
, description = Text.fields.vault.user
|
||||
|
@ -106,11 +106,11 @@ getAccountData key vault =
|
|||
|
||||
{-| Initiate a new Vault type.
|
||||
-}
|
||||
init : User -> Vault
|
||||
init user =
|
||||
init : Maybe User -> Vault
|
||||
init mUser =
|
||||
{ accountData = Dict.empty
|
||||
, rooms = Hashdict.empty .roomId
|
||||
, user = user
|
||||
, user = mUser
|
||||
}
|
||||
|
||||
|
||||
|
@ -156,4 +156,4 @@ update vu vault =
|
|||
setAccountData key value vault
|
||||
|
||||
SetUser user ->
|
||||
{ vault | user = user }
|
||||
{ vault | user = Just user }
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
module Matrix exposing
|
||||
( Vault, fromUserId
|
||||
( Vault, fromUserId, fromUsername
|
||||
, VaultUpdate, update
|
||||
, addAccessToken, sendMessageEvent
|
||||
)
|
||||
|
@ -19,7 +19,7 @@ support a monolithic public registry. (:
|
|||
|
||||
## Vault
|
||||
|
||||
@docs Vault, fromUserId
|
||||
@docs Vault, fromUserId, fromUsername
|
||||
|
||||
|
||||
## Keeping the Vault up-to-date
|
||||
|
@ -57,6 +57,9 @@ type alias VaultUpdate =
|
|||
Types.VaultUpdate
|
||||
|
||||
|
||||
{-| Adds a custom access token to the Vault. This can be done if no password is
|
||||
provided or known.
|
||||
-}
|
||||
addAccessToken : String -> Vault -> Vault
|
||||
addAccessToken token (Vault vault) =
|
||||
Envelope.mapContext (\c -> { c | suggestedAccessToken = Just token }) vault
|
||||
|
@ -74,16 +77,39 @@ addAccessToken token (Vault vault) =
|
|||
|
||||
-}
|
||||
fromUserId : String -> Maybe Vault
|
||||
fromUserId =
|
||||
User.fromString
|
||||
>> Maybe.map
|
||||
fromUserId uid =
|
||||
uid
|
||||
|> User.fromString
|
||||
|> Maybe.map
|
||||
(\u ->
|
||||
Envelope.init
|
||||
{ serverName = "https://" ++ User.domain u
|
||||
, content = Internal.init u
|
||||
, content = Internal.init (Just u)
|
||||
}
|
||||
|> Envelope.mapContext (\c -> { c | username = Just uid })
|
||||
)
|
||||
>> Maybe.map Vault
|
||||
|> Maybe.map Vault
|
||||
|
||||
|
||||
{-| Using a username and an address, create a Vault.
|
||||
|
||||
The username can either be the localpart or the full Matrix ID. For example,
|
||||
you can either insert `alice` or `@alice:example.org`.
|
||||
|
||||
-}
|
||||
fromUsername : { username : String, host : String, port_ : Maybe Int } -> Vault
|
||||
fromUsername { username, host, port_ } =
|
||||
{ serverName =
|
||||
port_
|
||||
|> Maybe.map String.fromInt
|
||||
|> Maybe.map ((++) ":")
|
||||
|> Maybe.withDefault ""
|
||||
|> (++) host
|
||||
, content = Internal.init (User.fromString username)
|
||||
}
|
||||
|> Envelope.init
|
||||
|> Envelope.mapContext (\c -> { c | username = Just username })
|
||||
|> Vault
|
||||
|
||||
|
||||
{-| Send a message event to a room.
|
||||
|
@ -94,15 +120,25 @@ exists and the user is able to send a message to, and instead just sends the
|
|||
request to the Matrix API.
|
||||
|
||||
-}
|
||||
sendMessageEvent : Vault -> { content : E.Value, eventType : String, roomId : String, toMsg : VaultUpdate -> msg, transactionId : String } -> Cmd msg
|
||||
sendMessageEvent (Vault vault) data =
|
||||
Api.sendMessageEvent vault
|
||||
{ content = data.content
|
||||
, eventType = data.eventType
|
||||
, roomId = data.roomId
|
||||
, toMsg = Types.VaultUpdate >> data.toMsg
|
||||
, transactionId = data.transactionId
|
||||
}
|
||||
sendMessageEvent :
|
||||
{ content : E.Value
|
||||
, eventType : String
|
||||
, roomId : String
|
||||
, toMsg : VaultUpdate -> msg
|
||||
, transactionId : String
|
||||
, vault : Vault
|
||||
}
|
||||
-> Cmd msg
|
||||
sendMessageEvent data =
|
||||
case data.vault of
|
||||
Vault vault ->
|
||||
Api.sendMessageEvent vault
|
||||
{ content = data.content
|
||||
, eventType = data.eventType
|
||||
, roomId = data.roomId
|
||||
, toMsg = Types.VaultUpdate >> data.toMsg
|
||||
, transactionId = data.transactionId
|
||||
}
|
||||
|
||||
|
||||
{-| Using new VaultUpdate information, update the Vault accordingly.
|
||||
|
|
|
@ -2,6 +2,8 @@ module Matrix.Settings exposing
|
|||
( setAccessToken, removeAccessToken
|
||||
, getDeviceName, setDeviceName
|
||||
, getSyncTime, setSyncTime
|
||||
, setPassword
|
||||
, removePassword, removePasswordOnLogin
|
||||
)
|
||||
|
||||
{-| The Matrix Vault has lots of configurable variables that you rarely want to
|
||||
|
@ -50,20 +52,39 @@ The value is in miliseconds, so it is set at 30,000.
|
|||
|
||||
@docs getSyncTime, setSyncTime
|
||||
|
||||
|
||||
## Password
|
||||
|
||||
When a Vault wants to access the Matrix API, it needs an access token. This can
|
||||
either be provided directly, or the Vault can get one itself by using a password
|
||||
to log in.
|
||||
|
||||
@docs setPassword
|
||||
|
||||
For security reasons, it is not possible to read whatever password is stored in
|
||||
the Vault. An attacker with access to the memory might be able to find it,
|
||||
however, so the Vault offers ways to remove the password from memory.
|
||||
|
||||
@docs removePassword, removePasswordOnLogin
|
||||
|
||||
-}
|
||||
|
||||
import Internal.Values.Envelope as Envelope
|
||||
import Types exposing (Vault(..))
|
||||
|
||||
|
||||
{-| Insert a suggested access token.
|
||||
{-| Determine the device name.
|
||||
-}
|
||||
setAccessToken : String -> Vault -> Vault
|
||||
setAccessToken token (Vault vault) =
|
||||
vault
|
||||
|> Envelope.mapContext
|
||||
(\c -> { c | suggestedAccessToken = Just token })
|
||||
|> Vault
|
||||
getDeviceName : Vault -> String
|
||||
getDeviceName (Vault vault) =
|
||||
Envelope.extractSettings .deviceName vault
|
||||
|
||||
|
||||
{-| Determine the sync timeout value.
|
||||
-}
|
||||
getSyncTime : Vault -> Int
|
||||
getSyncTime (Vault vault) =
|
||||
Envelope.extractSettings .syncTime vault
|
||||
|
||||
|
||||
{-| Remove an access token that has been inserted using the
|
||||
|
@ -80,11 +101,32 @@ removeAccessToken (Vault vault) =
|
|||
|> Vault
|
||||
|
||||
|
||||
{-| Determine the device name.
|
||||
{-| Remove a password that is stored in the Matrix Vault.
|
||||
-}
|
||||
getDeviceName : Vault -> String
|
||||
getDeviceName (Vault vault) =
|
||||
Envelope.extractSettings .deviceName vault
|
||||
removePassword : Vault -> Vault
|
||||
removePassword (Vault vault) =
|
||||
vault
|
||||
|> Envelope.mapContext
|
||||
(\c -> { c | password = Nothing })
|
||||
|> Vault
|
||||
|
||||
|
||||
{-| Remove password from the Vault as soon as a valid access token has been
|
||||
received from the Matrix API.
|
||||
-}
|
||||
removePasswordOnLogin : Bool -> Vault -> Vault
|
||||
removePasswordOnLogin b (Vault vault) =
|
||||
Vault <| Envelope.mapSettings (\s -> { s | removePasswordOnLogin = b }) vault
|
||||
|
||||
|
||||
{-| Insert a suggested access token.
|
||||
-}
|
||||
setAccessToken : String -> Vault -> Vault
|
||||
setAccessToken token (Vault vault) =
|
||||
vault
|
||||
|> Envelope.mapContext
|
||||
(\c -> { c | suggestedAccessToken = Just token })
|
||||
|> Vault
|
||||
|
||||
|
||||
{-| Override the device name.
|
||||
|
@ -94,11 +136,14 @@ setDeviceName name (Vault vault) =
|
|||
Vault <| Envelope.mapSettings (\s -> { s | deviceName = name }) vault
|
||||
|
||||
|
||||
{-| Determine the sync timeout value.
|
||||
{-| Set a password for the given user.
|
||||
-}
|
||||
getSyncTime : Vault -> Int
|
||||
getSyncTime (Vault vault) =
|
||||
Envelope.extractSettings .syncTime vault
|
||||
setPassword : String -> Vault -> Vault
|
||||
setPassword password (Vault vault) =
|
||||
vault
|
||||
|> Envelope.mapContext
|
||||
(\c -> { c | password = Just password })
|
||||
|> Vault
|
||||
|
||||
|
||||
{-| Override the sync timeout value.
|
||||
|
|
|
@ -19,4 +19,4 @@ vault =
|
|||
|> Fuzz.map Dict.fromList
|
||||
)
|
||||
(TestHashdict.fuzzer .roomId TestRoom.fuzzer)
|
||||
TestUser.fuzzer
|
||||
(Fuzz.maybe TestUser.fuzzer)
|
||||
|
|
Loading…
Reference in New Issue