Skip to content

Commit

Permalink
feat: Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
mitsuhiko committed Mar 12, 2018
0 parents commit b6f3c1b
Show file tree
Hide file tree
Showing 7 changed files with 604 additions and 0 deletions.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@

/target/
**/*.rs.bk
Cargo.lock
12 changes: 12 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[package]
name = "sentry-types"
version = "0.1.0"
authors = ["Sentry <[email protected]>"]

[dependencies]
failure = "0.1.1"
failure_derive = "0.1.1"
url = "1.6.0"
serde = "1.0.27"
serde_derive = "1.0.27"
serde_json = "1.0.9"
156 changes: 156 additions & 0 deletions src/auth.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
use std::fmt;
use std::str::FromStr;

/// Represents an auth header parsing error.
#[derive(Debug, Fail)]
pub enum AuthParseError {
/// Raised if the auth header is not indicating sentry auth
#[fail(display = "non sentry auth")]
NonSentryAuth,
/// Raised if the timestamp value is invalid.
#[fail(display = "invalid value for timestamp")]
InvalidTimestamp,
/// Raised if the version value is invalid
#[fail(display = "invalid value for version")]
InvalidVersion,
/// Raised if the version is missing entirely
#[fail(display = "no valid version defined")]
MissingVersion,
/// Raised if the public key is missing entirely
#[fail(display = "missing public key in auth header")]
MissingPublicKey,
}

/// Represents an auth header.
#[derive(Default, Debug)]
pub struct Auth {
timestamp: Option<f64>,
client: Option<String>,
version: u16,
key: String,
secret: Option<String>,
}

impl Auth {
/// Returns the unix timestamp the client defined
pub fn timestamp(&self) -> Option<f64> {
self.timestamp
}

/// Returns the protocol version the client speaks
pub fn version(&self) -> u16 {
self.version
}

/// Returns the public key
pub fn public_key(&self) -> &str {
&self.key
}

/// Returns the client's secret if it authenticated with a secret.
pub fn secret_key(&self) -> Option<&str> {
self.secret.as_ref().map(|x| x.as_str())
}

/// Returns true if the authentication implies public auth (no secret)
pub fn is_public(&self) -> bool {
self.secret.is_none()
}

/// Returns the client's relay
pub fn client_relay(&self) -> Option<&str> {
self.client.as_ref().map(|x| x.as_str())
}
}

impl fmt::Display for Auth {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"Sentry sentry_key={}, sentry_version={}",
self.key, self.version
)?;
if let Some(ts) = self.timestamp {
write!(f, ", sentry_timestamp={}", ts)?;
}
if let Some(ref client) = self.client {
write!(f, ", sentry_client={}", client)?;
}
if let Some(ref secret) = self.secret {
write!(f, ", sentry_secret={}", secret)?;
}
Ok(())
}
}

impl FromStr for Auth {
type Err = AuthParseError;

fn from_str(s: &str) -> Result<Auth, AuthParseError> {
let mut rv = Auth::default();
let mut base_iter = s.splitn(2, ' ');
if !base_iter
.next()
.unwrap_or("")
.eq_ignore_ascii_case("sentry")
{
return Err(AuthParseError::NonSentryAuth);
}
let items = base_iter.next().unwrap_or("");
for item in items.split(',') {
let mut kviter = item.trim().split('=');
match (kviter.next(), kviter.next()) {
(Some("sentry_timestamp"), Some(ts)) => {
rv.timestamp = Some(ts.parse().map_err(|_| AuthParseError::InvalidTimestamp)?);
}
(Some("sentry_client"), Some(client)) => {
rv.client = Some(client.into());
}
(Some("sentry_version"), Some(version)) => {
rv.version = version.parse().map_err(|_| AuthParseError::InvalidVersion)?;
}
(Some("sentry_key"), Some(key)) => {
rv.key = key.into();
}
(Some("sentry_secret"), Some(secret)) => {
rv.secret = Some(secret.into());
}
_ => {}
}
}

if rv.key.is_empty() {
return Err(AuthParseError::MissingPublicKey);
}
if rv.version == 0 {
return Err(AuthParseError::MissingVersion);
}

Ok(rv)
}
}

#[test]
fn test_auth_parsing() {
let auth: Auth = "Sentry sentry_timestamp=1328055286.51, \
sentry_client=raven-python/42, \
sentry_version=6, \
sentry_key=public, \
sentry_secret=secret"
.parse()
.unwrap();
assert_eq!(auth.timestamp(), Some(1328055286.51));
assert_eq!(auth.client_relay(), Some("raven-python/42"));
assert_eq!(auth.version(), 6);
assert_eq!(auth.public_key(), "public");
assert_eq!(auth.secret_key(), Some("secret"));

assert_eq!(
auth.to_string(),
"Sentry sentry_key=public, \
sentry_version=6, \
sentry_timestamp=1328055286.51, \
sentry_client=raven-python/42, \
sentry_secret=secret"
);
}
Loading

0 comments on commit b6f3c1b

Please sign in to comment.