Expose Matrix.User module
parent
ae19884a18
commit
259f695b74
2
elm.json
2
elm.json
|
@ -27,10 +27,12 @@
|
||||||
"Internal.Values.Settings",
|
"Internal.Values.Settings",
|
||||||
"Internal.Values.StateManager",
|
"Internal.Values.StateManager",
|
||||||
"Internal.Values.Timeline",
|
"Internal.Values.Timeline",
|
||||||
|
"Internal.Values.User",
|
||||||
"Internal.Values.Vault",
|
"Internal.Values.Vault",
|
||||||
"Matrix",
|
"Matrix",
|
||||||
"Matrix.Event",
|
"Matrix.Event",
|
||||||
"Matrix.Settings",
|
"Matrix.Settings",
|
||||||
|
"Matrix.User",
|
||||||
"Types"
|
"Types"
|
||||||
],
|
],
|
||||||
"elm-version": "0.19.0 <= v < 0.20.0",
|
"elm-version": "0.19.0 <= v < 0.20.0",
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
module Internal.Config.Text exposing
|
module Internal.Config.Text exposing
|
||||||
( docs, failures, fields, mappings, logs
|
( docs, failures, fields, mappings, logs, parses
|
||||||
, accessTokenFoundLocally, accessTokenExpired, accessTokenInvalid
|
, accessTokenFoundLocally, accessTokenExpired, accessTokenInvalid
|
||||||
, versionsFoundLocally, versionsReceived, versionsFailedToDecode
|
, versionsFoundLocally, versionsReceived, versionsFailedToDecode
|
||||||
, unsupportedVersionForEndpoint
|
, unsupportedVersionForEndpoint
|
||||||
, decodedDictSize, invalidHashInHashdict, invalidHashInMashdict, leakingValueFound
|
, decodedDictSize, invalidHashInHashdict, invalidHashInMashdict, leakingValueFound
|
||||||
, parses
|
|
||||||
)
|
)
|
||||||
|
|
||||||
{-| Throughout the Elm SDK, there are lots of pieces of text being used for
|
{-| 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
|
## Type documentation
|
||||||
|
|
||||||
@docs docs, failures, fields, mappings, logs
|
@docs docs, failures, fields, mappings, logs, parses
|
||||||
|
|
||||||
|
|
||||||
## API Authentication
|
## API Authentication
|
||||||
|
@ -487,23 +486,6 @@ leakingValueFound leaking_value =
|
||||||
"Found leaking value : " ++ 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
|
{-| 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,
|
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.
|
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
|
{-| 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,
|
SDK aims to communicate accordingly. This may fail in some scenarios, however,
|
||||||
in which case it will throw this error.
|
in which case it will throw this error.
|
||||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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.
|
{-| 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)
|
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
|
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.
|
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.Envelope as Envelope
|
||||||
import Internal.Values.Event as Event
|
import Internal.Values.Event as Event
|
||||||
|
import Internal.Values.User as User
|
||||||
import Internal.Values.Vault as Vault
|
import Internal.Values.Vault as Vault
|
||||||
|
|
||||||
|
|
||||||
|
@ -27,6 +28,12 @@ type Event
|
||||||
= Event (Envelope.Envelope Event.Event)
|
= Event (Envelope.Envelope Event.Event)
|
||||||
|
|
||||||
|
|
||||||
|
{-| Opaque type for Matrix User
|
||||||
|
-}
|
||||||
|
type User
|
||||||
|
= User (Envelope.Envelope User.User)
|
||||||
|
|
||||||
|
|
||||||
{-| Opaque type for Matrix Vault
|
{-| Opaque type for Matrix Vault
|
||||||
-}
|
-}
|
||||||
type Vault
|
type Vault
|
||||||
|
|
Loading…
Reference in New Issue