Expose Matrix.User module

parser
Bram 2024-04-12 13:15:26 +02:00
parent ae19884a18
commit 259f695b74
5 changed files with 255 additions and 22 deletions

View File

@ -27,10 +27,12 @@
"Internal.Values.Settings",
"Internal.Values.StateManager",
"Internal.Values.Timeline",
"Internal.Values.User",
"Internal.Values.Vault",
"Matrix",
"Matrix.Event",
"Matrix.Settings",
"Matrix.User",
"Types"
],
"elm-version": "0.19.0 <= v < 0.20.0",

View File

@ -1,10 +1,9 @@
module Internal.Config.Text exposing
( docs, failures, fields, mappings, logs
( docs, failures, fields, mappings, logs, parses
, accessTokenFoundLocally, accessTokenExpired, accessTokenInvalid
, versionsFoundLocally, versionsReceived, versionsFailedToDecode
, unsupportedVersionForEndpoint
, decodedDictSize, invalidHashInHashdict, invalidHashInMashdict, leakingValueFound
, parses
)
{-| Throughout the Elm SDK, there are lots of pieces of text being used for
@ -28,7 +27,7 @@ You should only do this if you know what you're doing.
## Type documentation
@docs docs, failures, fields, mappings, logs
@docs docs, failures, fields, mappings, logs, parses
## API Authentication
@ -487,23 +486,6 @@ leakingValueFound leaking_value =
"Found leaking value : " ++ leaking_value
parses :
{ reservedIPs :
{ ipv6Toipv4 : String
, multicast : String
, futureUse : String
, unspecified : String
}
}
parses =
{ reservedIPs =
{ ipv6Toipv4 = "Detected a reserved ip address that is formerly used as an IPv6 to IPv4 relay. It is unlikely that this IP Address is real."
, multicast = "Detected a reserved ip address that is used for multicasting. It is unlikely that this IP Address is real."
, futureUse = "Detected a reserves ip address that is reserved for future use. It is unlikely that this IP Address is real if you're running a recent version of the Elm SDK."
, unspecified = "This is an unspecified ip address. It is unlikely that this IP Address is real and someone might try to break something."
}
}
{-| These logs might appear during a process where something unexpected has
happened. Most of these unexpected results, are taken account of by the Elm SDK,
but logged so that the programmer can do something about it.
@ -533,6 +515,28 @@ mappings =
}
{-| Logs for issues that might be found while parsing strings into meaningful data.
-}
parses :
{ historicalUserId : String -> String
, reservedIPs :
{ ipv6Toipv4 : String
, multicast : String
, futureUse : String
, unspecified : String
}
}
parses =
{ historicalUserId = \name -> "Found a historical username `" ++ name ++ "`."
, reservedIPs =
{ ipv6Toipv4 = "Detected a reserved ip address that is formerly used as an IPv6 to IPv4 relay. It is unlikely that this IP Address is real."
, multicast = "Detected a reserved ip address that is used for multicasting. It is unlikely that this IP Address is real."
, futureUse = "Detected a reserves ip address that is reserved for future use. It is unlikely that this IP Address is real if you're running a recent version of the Elm SDK."
, unspecified = "This is an unspecified ip address. It is unlikely that this IP Address is real and someone might try to break something."
}
}
{-| The Matrix homeserver can specify how it wishes to communicate, and the Elm
SDK aims to communicate accordingly. This may fail in some scenarios, however,
in which case it will throw this error.

View File

@ -0,0 +1,73 @@
module Internal.Values.User exposing
( User, toString, fromString
, localpart, domain
)
{-| The Matrix user is uniquely identified by their identifier. This User type
helps identify and safely handle these strings to transform them into meaningful
data types.
## User
@docs User, toString, fromString
## Divide
Matrix users are identified by their unique ID. In the Matrix API, this is a
string that looks as follows:
@alice:example.org
\---/ \---------/
| |
| |
localpart domain
Since the username is safely parsed, one can get these parts of the username.
@docs localpart, domain
-}
import Internal.Grammar.ServerName as ServerName
import Internal.Grammar.UserId as UserId
{-| The Matrix user represents a user across multiple Matrix rooms.
-}
type alias User =
UserId.UserID
{-| The domain represents the Matrix homeserver controlling this user. It also
offers other Matrix homeservers an indication of where to look if you wish to
send a message to this user.
-}
domain : User -> String
domain =
.domain >> ServerName.toString
{-| Parse a string and convert it into a User, if formatted properly.
-}
fromString : String -> Maybe User
fromString =
UserId.fromString
{-| The localpart is similar to a username, in the sense that every user has
their own localpart. The localpart is not unique across multiple servers,
however! There can be a user @alice:example.com and a user @alice:example.org in
a room at the same time.
-}
localpart : User -> String
localpart =
.localpart
{-| Convert a user into its unique identifier string value.
-}
toString : User -> String
toString =
UserId.toString

147
src/Matrix/User.elm Normal file
View File

@ -0,0 +1,147 @@
module Matrix.User exposing
( User, toString
, localpart, domain
, get
)
{-| Matrix users are identified by their unique ID. In the Matrix API, this is a
string that looks as follows:
@alice:example.org
\---/ \---------/
| |
| |
localpart domain
Since it is very easy to abuse Matrix user IDs to sneak in arbitrary values,
the Elm SDK parses them and makes sure they are safe. As a result, you might
need this module to get the right information from a user!
## User
@docs User, toString
## Info
Sometimes, you are more interested in the username itself. These functions can
help you decipher, disambiguate and categorize users based on their username.
@docs localpart, domain
## Manipulate
@docs get
-}
import Internal.Values.Envelope as Envelope
import Internal.Values.User as Internal
import Types exposing (User(..))
{-| The User type represents a Matrix user.
It contains information like:
- Their username on Matrix
- The server that hosts their account
- Access tokens needed to talk to the server
It does **NOT** contain information like:
- Their nickname
- Their profile picture
- Your private room with them
You can get all that information by looking it up in the [Vault](Matrix#Vault).
**Note:** Please do not store this user type as a variable in your model! You
should always maintain a single source of truth in Elm, and the User type
contains various credentials and API tokens that might expire if you don't
update them from the Vault.
If you need to remember specific users, you can best compare their identifying
string using [toString](Matrix-User#toString) or you can use
[get](Matrix-User#get) with the Vault to get the user type.
-}
type alias User =
Types.User
{-| The domain is the name of the server that the user connects to. Server names
are case-sensitive, so if the strings are equal, the users are on the same
server!
As a result, you can use the user domain for:
- When multiple users in a room have the same localpart on different servers
- Finding other users from a potentially malicious homeserver
- Counting homeservers in a room
See the following examples:
domain (get vault "@alice:example.org") -- "example.org"
domain (get vault "@bob:127.0.0.1") -- "127.0.0.1"
domain (get vault "@charlie:[2001:db8::]") -- "[2001:db8::]"
-}
domain : User -> String
domain (User user) =
Envelope.extract Internal.domain user
{-| Get a specific user by their unique identifier.
The Vault is needed as an input because the `User` type also stores various
credentials needed to talk to the Matrix API.
get vault "@alice:example.org" -- Just (User "alice" "example.org")
get vault "@bob:127.0.0.1" -- Just (User "bob" "127.0.0.1")
get vault "@charlie:[2001:db8::]" -- Just (User "charlie" "2001:db8::")
get vault "@evil:#mp#ss#bl#.c#m" -- Nothing
get vault "" -- Nothing
-}
get : Types.Vault -> String -> Maybe User
get (Types.Vault vault) username =
Envelope.mapMaybe (\_ -> Internal.fromString username) vault
|> Maybe.map Types.User
{-| The localpart is the user's unique username. Every homeserver has their own
username registry, so you might occasionally find distinct users with the same
localpart.
The localpart is often used as a user's name in a room if they haven't set up
a custom name.
See the following examples:
localpart (get vault "@alice:example.org") -- "alice"
localpart (get vault "@bob:127.0.0.1") -- "bob"
localpart (get vault "@charlie:[2001:db8::]") -- "charlie"
-}
localpart : User -> String
localpart (User user) =
Envelope.extract Internal.localpart user
{-| Get the uniquely identifying string for this user. Since the strings are
case-sensitive, you can run a simple string comparison to compare usernames.
-}
toString : User -> String
toString (User user) =
Envelope.extract Internal.toString user

View File

@ -1,4 +1,4 @@
module Types exposing (Vault(..), Event(..))
module Types exposing (Vault(..), Event(..), User(..))
{-| The Elm SDK uses a lot of records and values that are easy to manipulate.
Yet, the [Elm design guidelines](https://package.elm-lang.org/help/design-guidelines#keep-tags-and-record-constructors-secret)
@ -12,12 +12,13 @@ access their content directly.
The opaque types are placed in a central module so all exposed modules can
safely access all exposed data types without risking to create circular imports.
@docs Vault, Event
@docs Vault, Event, User
-}
import Internal.Values.Envelope as Envelope
import Internal.Values.Event as Event
import Internal.Values.User as User
import Internal.Values.Vault as Vault
@ -27,6 +28,12 @@ type Event
= Event (Envelope.Envelope Event.Event)
{-| Opaque type for Matrix User
-}
type User
= User (Envelope.Envelope User.User)
{-| Opaque type for Matrix Vault
-}
type Vault