Merge pull request #25 from noordstar/4-transfer-api

Add password
pull/26/head
BramvdnHeuvel 2024-05-30 14:07:52 +02:00 committed by GitHub
commit acd4a07d5e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 176 additions and 39 deletions

4
.gitignore vendored
View File

@ -4,3 +4,7 @@ elm-stuff
repl-temp-*
# VScode settings
.vscode/
# Elm output
index.html
elm.js

View File

@ -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)

View File

@ -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

View File

@ -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."
]

View File

@ -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 } }

View File

@ -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
}

View File

@ -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 }

View File

@ -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.

View File

@ -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.

View File

@ -19,4 +19,4 @@ vault =
|> Fuzz.map Dict.fromList
)
(TestHashdict.fuzzer .roomId TestRoom.fuzzer)
TestUser.fuzzer
(Fuzz.maybe TestUser.fuzzer)