Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
502 changes: 412 additions & 90 deletions Cargo.lock

Large diffs are not rendered by default.

9 changes: 5 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,12 @@ version = "0.1.0"
[dependencies]
clap = "2.29.2"
failure = "0.1.1"
pretty_env_logger = "0.2.0"

[dependencies.smith-aorta]
path = "aorta"
version = "0.1.0"

[dependencies.smith-trove]
path = "trove"
version = "0.1.0"

[dependencies.smith-common]
path = "common"
version = "0.1.0"
Expand All @@ -31,4 +28,8 @@ version = "0.1.0"
path = "server"
version = "0.1.0"

[dependencies.smith-trove]
path = "trove"
version = "0.1.0"

[workspace]
4 changes: 4 additions & 0 deletions aorta/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,16 @@ version = "0.1.0"
base64 = "0.9.0"
failure = "0.1.1"
failure_derive = "0.1.1"
futures = "0.1.17"
hyper = "0.11.18"
hyper-tls = "0.1.2"
parking_lot = "0.5.3"
rand = "0.4.2"
serde = "1.0.27"
serde_derive = "1.0.27"
serde_json = "1.0.9"
sodiumoxide = "0.0.16"
tokio-core = "0.1.12"
url = "1.6.0"

[dependencies.chrono]
Expand Down
1 change: 1 addition & 0 deletions aorta/src/auth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ pub struct PublicKey {
/// Secret keys are based on ed25519 but this should be considered an
/// implementation detail for now. We only ever represent public keys
/// on the wire as opaque ascii encoded strings of arbitrary format or length.
#[derive(Clone)]
pub struct SecretKey {
inner: sign_backend::SecretKey,
}
Expand Down
63 changes: 62 additions & 1 deletion aorta/src/config.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
use chrono::Duration;
use hyper::{Method, Request, Uri};
use hyper::header::{ContentLength, ContentType};
use serde::Serialize;
use serde_json;

use auth::{AgentId, PublicKey, SecretKey};
use upstream::UpstreamDescriptor;


/// Holds common config values that affect the aorta behavior.
///
/// This config is typically created by something and then passed down
Expand All @@ -14,13 +18,70 @@ pub struct AortaConfig {
pub snapshot_expiry: Duration,
/// The upstream descriptor for this aorta
pub upstream: UpstreamDescriptor<'static>,
/// The agent ID.
pub agent_id: Option<AgentId>,
/// The private key for authentication.
pub secret_key: Option<SecretKey>,
/// The public key for authentication.
pub public_key: Option<PublicKey>,
}

impl Default for AortaConfig {
fn default() -> AortaConfig {
AortaConfig {
snapshot_expiry: Duration::seconds(60),
upstream: Default::default(),
agent_id: None,
secret_key: None,
public_key: None,
}
}
}

impl AortaConfig {
/// Returns the agent id or panics.
pub fn agent_id(&self) -> &AgentId {
self.agent_id
.as_ref()
.expect("agent id must be set on aorta config")
}

/// Returns the public key or panics.
pub fn public_key(&self) -> &PublicKey {
self.public_key
.as_ref()
.expect("public key must be set on aorta config")
}

/// Returns the secret key or panics.
pub fn secret_key(&self) -> &SecretKey {
self.secret_key
.as_ref()
.expect("secret key must be set on aorta config")
}

/// Returns the URL to hit for an api request on the upstream.
pub fn get_api_uri(&self, path: &str) -> Uri {
format!(
"{}api/0/{}",
self.upstream,
path.trim_left_matches(&['/'][..])
).parse()
.unwrap()
}

/// Prepares a JSON bodied API request to aorta with signature.
pub fn prepare_aorta_req<S: Serialize>(&self, method: Method, path: &str, body: &S) -> Request {
let mut req = Request::new(method, self.get_api_uri(path));
let json = serde_json::to_vec(body).unwrap();
let signature = self.secret_key().sign(&json);
{
let headers = req.headers_mut();
headers.set_raw("X-Sentry-Agent-Signature", signature);
headers.set(ContentType::json());
headers.set(ContentLength(json.len() as u64));
}
req.set_body(json);
req
}
}
3 changes: 3 additions & 0 deletions aorta/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ extern crate chrono;
extern crate failure;
#[macro_use]
extern crate failure_derive;
extern crate futures;
extern crate hyper;
extern crate parking_lot;
extern crate rand;
extern crate serde;
Expand All @@ -13,6 +15,7 @@ extern crate serde_json;
#[macro_use]
extern crate smith_common;
extern crate sodiumoxide;
extern crate tokio_core;
extern crate url;
extern crate uuid;

Expand Down
2 changes: 2 additions & 0 deletions cabi/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Cargo.lock
target
22 changes: 22 additions & 0 deletions cabi/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
[package]
name = "smith-cabi"
version = "0.1.0"
license = "MIT"
authors = ["Sentry <hello@sentry.io>"]
homepage = "https://github.com/getsentry/sentry-agent"
repository = "https://github.com/getsentry/sentry-agent"
description = "Exposes some internals of the agent to C."

[lib]
name = "smith"
crate-type = ["cdylib"]

[workspace]

[profile.release]
debug = true
lto = true

[dependencies]
smith-aorta = { version = "0.1.0", path = "../aorta" }
failure = "0.1.1"
159 changes: 159 additions & 0 deletions cabi/src/core.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
use std::mem;
use std::ptr;
use std::str;
use std::slice;
use std::ffi::CStr;
use std::os::raw::c_char;

use utils::{set_panic_hook, LAST_ERROR};

/// Represents a string.
#[repr(C)]
pub struct SmithStr {
pub data: *mut c_char,
pub len: usize,
pub owned: bool,
}

impl Default for SmithStr {
fn default() -> SmithStr {
SmithStr {
data: ptr::null_mut(),
len: 0,
owned: false,
}
}
}

impl SmithStr {
pub fn new(s: &str) -> SmithStr {
SmithStr {
data: s.as_ptr() as *mut c_char,
len: s.len(),
owned: false,
}
}

pub fn from_string(mut s: String) -> SmithStr {
s.shrink_to_fit();
let rv = SmithStr {
data: s.as_ptr() as *mut c_char,
len: s.len(),
owned: true,
};
mem::forget(s);
rv
}

pub unsafe fn free(&mut self) {
if self.owned {
String::from_raw_parts(self.data as *mut _, self.len, self.len);
self.data = ptr::null_mut();
self.len = 0;
self.owned = false;
}
}

pub fn as_str(&self) -> &str {
unsafe {
str::from_utf8_unchecked(slice::from_raw_parts(
self.data as *const _, self.len))
}
}
}

/// Initializes the library
#[no_mangle]
pub unsafe extern "C" fn smith_init() {
set_panic_hook();
}

/// Returns the last error code.
///
/// If there is no error, 0 is returned.
#[no_mangle]
pub unsafe extern "C" fn smith_err_failed() -> bool {
LAST_ERROR.with(|e| {
if let Some(..) = *e.borrow() {
true
} else {
false
}
})
}

/// Returns the last error message.
///
/// If there is no error an empty string is returned. This allocates new memory
/// that needs to be freed with `smith_str_free`.
#[no_mangle]
pub unsafe extern "C" fn smith_err_get_last_message() -> SmithStr {
use std::fmt::Write;
use std::error::Error;
LAST_ERROR.with(|e| {
if let Some(ref err) = *e.borrow() {
let mut msg = err.to_string();
for cause in err.causes().skip(1) {
write!(&mut msg, "\n caused by: {}", cause).ok();
}
SmithStr::from_string(msg)
} else {
Default::default()
}
})
}

/// Returns the panic information as string.
#[no_mangle]
pub unsafe extern "C" fn smith_err_get_backtrace() -> SmithStr {
LAST_ERROR.with(|e| {
if let Some(ref error) = *e.borrow() {
let backtrace = error.backtrace().to_string();
if !backtrace.is_empty() {
use std::fmt::Write;
let mut out = String::new();
write!(&mut out, "stacktrace: {}", backtrace).ok();
SmithStr::from_string(out)
} else {
Default::default()
}
} else {
Default::default()
}
})
}

/// Clears the last error.
#[no_mangle]
pub unsafe extern "C" fn smith_err_clear() {
LAST_ERROR.with(|e| {
*e.borrow_mut() = None;
});
}

ffi_fn! {
/// Creates a smith str from a c string.
///
/// This sets the string to owned. In case it's not owned you either have
/// to make sure you are not freeing the memory or you need to set the
/// owned flag to false.
unsafe fn smith_str_from_cstr(s: *const c_char) -> Result<SmithStr> {
let s = CStr::from_ptr(s).to_str()?;
Ok(SmithStr {
data: s.as_ptr() as *mut _,
len: s.len(),
owned: true,
})
}
}

/// Frees a smith str.
///
/// If the string is marked as not owned then this function does not
/// do anything.
#[no_mangle]
pub unsafe extern "C" fn smith_str_free(s: *mut SmithStr) {
if !s.is_null() {
(*s).free()
}
}
8 changes: 8 additions & 0 deletions cabi/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#[macro_use] extern crate failure;
extern crate smith_aorta;

#[macro_use] mod utils;

mod core;

pub use core::*;
Loading