ruma-identifiers
This commit is contained in:
commit
9ad1e0fc69
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
/target
|
130
Cargo.lock
generated
Normal file
130
Cargo.lock
generated
Normal file
@ -0,0 +1,130 @@
|
||||
[root]
|
||||
name = "ruma-identifiers"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"regex 0.1.73 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"url 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "idna"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"matches 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-bidi 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-normalization 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "kernel32-sys"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "matches"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "0.1.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "0.1.73"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"aho-corasick 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"regex-syntax 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"thread_local 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"utf8-ranges 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "thread-id"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thread_local"
|
||||
version = "0.2.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"thread-id 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-bidi"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"matches 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-normalization"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "url"
|
||||
version = "1.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"idna 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"matches 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "utf8-ranges"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.2.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-build"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
16
Cargo.toml
Normal file
16
Cargo.toml
Normal file
@ -0,0 +1,16 @@
|
||||
[package]
|
||||
authors = ["Jimmy Cuadra <jimmy@jimmycuadra.com>"]
|
||||
description = "Opaque identifiers for Matrix."
|
||||
documentation = "http://ruma.github.io/ruma-identifiers/ruma_identifiers"
|
||||
homepage = "https://github.com/ruma/ruma-identifiers"
|
||||
keywords = ["matrix", "matrix.org", "chat", "messaging", "ruma"]
|
||||
license = "MIT"
|
||||
name = "ruma-identifiers"
|
||||
readme = "README.md"
|
||||
repository = "https://github.com/ruma/ruma-identifiers"
|
||||
version = "0.1.0"
|
||||
|
||||
[dependencies]
|
||||
lazy_static = "0.2.1"
|
||||
regex = "0.1.73"
|
||||
url = "1.1.1"
|
20
LICENSE
Normal file
20
LICENSE
Normal file
@ -0,0 +1,20 @@
|
||||
Copyright (c) 2016 Jimmy Cuadra
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
7
README.md
Normal file
7
README.md
Normal file
@ -0,0 +1,7 @@
|
||||
# ruma-identifiers
|
||||
|
||||
**ruma-identifiers** contains types for [Matrix](https://matrix.org/) opaque identifiers, such as user IDs, room IDs, and room aliases.
|
||||
|
||||
## License
|
||||
|
||||
[MIT](http://opensource.org/licenses/MIT)
|
174
src/lib.rs
Normal file
174
src/lib.rs
Normal file
@ -0,0 +1,174 @@
|
||||
//! Crate **ruma_identifiers** contains types for [Matrix](https://matrix.org/) opaque identifiers,
|
||||
//! such as user IDs, room IDs, and room aliases.
|
||||
|
||||
#![deny(missing_docs)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate lazy_static;
|
||||
extern crate regex;
|
||||
extern crate url;
|
||||
|
||||
use std::fmt::{Display, Formatter, Result as FmtResult};
|
||||
|
||||
use regex::Regex;
|
||||
use url::{Host, ParseError, Url};
|
||||
|
||||
lazy_static! {
|
||||
static ref USER_ID_PATTERN: Regex =
|
||||
Regex::new(r"\A@(?P<localpart>[a-z0-9._=-]+):(?P<host>.+)\z")
|
||||
.expect("Failed to compile user ID regex.");
|
||||
}
|
||||
|
||||
/// An error encountered when trying to parse an invalid user ID string.
|
||||
#[derive(Debug)]
|
||||
pub enum Error {
|
||||
/// The user ID string did not match the "@<localpart>:<domain>" format, or used invalid
|
||||
/// characters in its localpart.
|
||||
InvalidFormat,
|
||||
/// The domain part of the user ID string was not a valid IP address or DNS name.
|
||||
InvalidHost(ParseError),
|
||||
}
|
||||
|
||||
/// A Matrix user ID.
|
||||
///
|
||||
/// A `UserId` is created from a string slice, and can be converted back into a string as needed:
|
||||
///
|
||||
/// ```
|
||||
/// # use ruma_identifiers::UserId;
|
||||
/// assert_eq!(UserId::new("@carl:example.com").unwrap().to_string(), "@carl:example.com");
|
||||
/// ```
|
||||
#[derive(Debug)]
|
||||
pub struct UserId {
|
||||
hostname: Host,
|
||||
localpart: String,
|
||||
port: u16,
|
||||
}
|
||||
|
||||
impl UserId {
|
||||
/// Create a new Matrix user ID from a string representation.
|
||||
///
|
||||
/// The string must include the leading @ sigil, the localpart, a literal colon, and a valid
|
||||
/// server name.
|
||||
pub fn new(user_id: &str) -> Result<UserId, Error> {
|
||||
let captures = match USER_ID_PATTERN.captures(user_id) {
|
||||
Some(captures) => captures,
|
||||
None => return Err(Error::InvalidFormat),
|
||||
};
|
||||
|
||||
let raw_host = captures.name("host").expect("Failed to extract hostname from regex.");
|
||||
|
||||
let url_string = format!("https://{}", raw_host);
|
||||
|
||||
let url = try!(Url::parse(&url_string));
|
||||
|
||||
let host = match url.host() {
|
||||
Some(host) => host,
|
||||
None => return Err(Error::InvalidFormat),
|
||||
};
|
||||
|
||||
let port = url.port().unwrap_or(443);
|
||||
|
||||
Ok(UserId {
|
||||
hostname: host.to_owned(),
|
||||
port: port,
|
||||
localpart: captures
|
||||
.name("localpart")
|
||||
.expect("Failed to extract localpart from regex.")
|
||||
.to_string(),
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns a `url::Host` for the user ID, containing the server name (minus the port) of the
|
||||
/// user's homeserver.
|
||||
///
|
||||
/// This host can be either a domain name, an IPv4 address, or an IPv6 address.
|
||||
pub fn hostname(&self) -> &Host {
|
||||
&self.hostname
|
||||
}
|
||||
|
||||
/// Returns the user's localpart.
|
||||
pub fn localpart(&self) -> &str {
|
||||
&self.localpart
|
||||
}
|
||||
|
||||
/// Returns the port the user's homeserver can be accessed on.
|
||||
pub fn port(&self) -> u16 {
|
||||
self.port
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ParseError> for Error {
|
||||
fn from(error: ParseError) -> Error {
|
||||
Error::InvalidHost(error)
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for UserId {
|
||||
fn fmt(&self, f: &mut Formatter) -> FmtResult {
|
||||
if self.port == 443 {
|
||||
write!(f, "@{}:{}", self.localpart, self.hostname)
|
||||
} else {
|
||||
write!(f, "@{}:{}:{}", self.localpart, self.hostname, self.port)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::UserId;
|
||||
|
||||
#[test]
|
||||
fn valid_user_id() {
|
||||
assert_eq!(
|
||||
UserId::new("@carl:example.com")
|
||||
.expect("Failed to create UserId.")
|
||||
.to_string(),
|
||||
"@carl:example.com"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn valid_user_id_with_explicit_standard_port() {
|
||||
assert_eq!(
|
||||
UserId::new("@carl:example.com:443")
|
||||
.expect("Failed to create UserId.")
|
||||
.to_string(),
|
||||
"@carl:example.com"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn valid_user_id_with_non_standard_port() {
|
||||
assert_eq!(
|
||||
UserId::new("@carl:example.com:5000")
|
||||
.expect("Failed to create UserId.")
|
||||
.to_string(),
|
||||
"@carl:example.com:5000"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn invalid_characters_in_localpart() {
|
||||
assert!(UserId::new("@CARL:example.com").is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn missing_sigil() {
|
||||
assert!(UserId::new("carl:example.com").is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn missing_domain() {
|
||||
assert!(UserId::new("carl").is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn invalid_host() {
|
||||
assert!(UserId::new("@carl:-").is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn invalid_port() {
|
||||
assert!(UserId::new("@carl:example.com:notaport").is_err());
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user