Skip to content

Commit 1decd97

Browse files
committed
Add abi for credentials
1 parent 1d08167 commit 1decd97

5 files changed

Lines changed: 118 additions & 1 deletion

File tree

crates/bindings-sys/src/lib.rs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -588,6 +588,15 @@ pub mod raw {
588588
///
589589
/// - `out_ptr` is NULL or `out` is not in bounds of WASM memory.
590590
pub fn identity(out_ptr: *mut u8);
591+
592+
/// Check the size of the jwt associated with the given connection.
593+
/// Returns 0 if there is no jwt for the connection.
594+
pub fn jwt_len(connection_id_ptr: *const u8, out_ptr: *mut u32);
595+
596+
/// Write the jwt payload for the given connection id to the out_ptr.
597+
/// target_ptr_len will be set to the number of bytes written to the buffer.
598+
/// If the buffer is too small, or the connection has no jwt, target_ptr_len will be set to 0.
599+
pub fn get_jwt(connection_id_ptr: *const u8, target_ptr: *mut u8, target_ptr_len: *mut u32);
591600
}
592601

593602
/// What strategy does the database index use?
@@ -1089,6 +1098,34 @@ pub fn identity() -> [u8; 32] {
10891098
buf
10901099
}
10911100

1101+
#[inline]
1102+
pub fn jwt_length(connection_id: [u8; 16]) -> Option<u32> {
1103+
let mut v: u32 = 0;
1104+
unsafe { raw::jwt_len(connection_id.as_ptr(), &mut v) }
1105+
if v == 0 {
1106+
None
1107+
} else {
1108+
Some(v)
1109+
}
1110+
}
1111+
1112+
#[inline]
1113+
pub fn get_jwt(connection_id: [u8; 16]) -> Option<String> {
1114+
let Some(jwt_len) = jwt_length(connection_id) else {
1115+
return None; // No JWT found.
1116+
};
1117+
let mut buf = vec![0u8; jwt_len as usize];
1118+
1119+
let mut v: u32 = buf.len() as u32;
1120+
unsafe {
1121+
raw::get_jwt(connection_id.as_ptr(), buf.as_mut_ptr(), &mut v);
1122+
}
1123+
if v == 0 {
1124+
return None; // No JWT found.
1125+
}
1126+
Some(std::str::from_utf8(&buf[..v as usize]).unwrap().to_string())
1127+
}
1128+
10921129
pub struct RowIter {
10931130
raw: raw::RowIter,
10941131
}

crates/core/src/host/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,8 @@ pub enum AbiCall {
144144
ConsoleTimerStart,
145145
ConsoleTimerEnd,
146146
Identity,
147+
JwtLength,
148+
GetJwt,
147149

148150
VolatileNonatomicScheduleImmediate,
149151
}

crates/core/src/host/wasm_common.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -392,6 +392,8 @@ macro_rules! abi_funcs {
392392
"spacetime_10.0"::datastore_btree_scan_bsatn,
393393
"spacetime_10.0"::datastore_delete_by_btree_scan_bsatn,
394394
"spacetime_10.0"::identity,
395+
"spacetime_10.0"::get_jwt,
396+
"spacetime_10.0"::jwt_len,
395397

396398
// unstable:
397399
"spacetime_10.0"::volatile_nonatomic_schedule_immediate,

crates/core/src/host/wasmtime/mod.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,18 @@ impl WasmPointee for spacetimedb_lib::Identity {
179179
}
180180
}
181181

182+
impl WasmPointee for spacetimedb_lib::ConnectionId {
183+
type Pointer = u32;
184+
fn write_to(self, mem: &mut MemView, ptr: Self::Pointer) -> Result<(), MemError> {
185+
let bytes = self.as_le_byte_array();
186+
mem.deref_slice_mut(ptr, bytes.len() as u32)?.copy_from_slice(&bytes);
187+
Ok(())
188+
}
189+
fn read_from(mem: &mut MemView, ptr: Self::Pointer) -> Result<Self, MemError> {
190+
Ok(Self::from_le_byte_array(*mem.deref_array(ptr)?))
191+
}
192+
}
193+
182194
type WasmPtr<T> = <T as WasmPointee>::Pointer;
183195

184196
/// Wraps access to WASM linear memory with some additional functionality.

crates/core/src/host/wasmtime/wasm_instance_env.rs

Lines changed: 65 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use crate::host::wasm_common::{
1212
};
1313
use crate::host::AbiCall;
1414
use anyhow::Context as _;
15-
use spacetimedb_lib::Timestamp;
15+
use spacetimedb_lib::{ConnectionId, Timestamp};
1616
use spacetimedb_primitives::{errno, ColId};
1717
use wasmtime::{AsContext, Caller, StoreContextMut};
1818

@@ -22,6 +22,7 @@ use super::{Mem, MemView, NullableMemOp, WasmError, WasmPointee, WasmPtr};
2222
use instrumentation::noop as span;
2323
#[cfg(feature = "spacetimedb-wasm-instance-env-times")]
2424
use instrumentation::op as span;
25+
use spacetimedb_datastore::locking_tx_datastore::state_view::StateView;
2526

2627
/// A `WasmInstanceEnv` provides the connection between a module
2728
/// and the database.
@@ -1208,6 +1209,69 @@ impl WasmInstanceEnv {
12081209
})
12091210
}
12101211

1212+
pub fn jwt_len(
1213+
caller: Caller<'_, Self>,
1214+
connection_id: WasmPtr<ConnectionId>,
1215+
out_ptr: WasmPtr<u32>,
1216+
) -> RtResult<()> {
1217+
log::info!("Calling has_jwt");
1218+
Self::with_span(caller, AbiCall::JwtLength, |caller| {
1219+
let (mem, env) = Self::mem_env(caller);
1220+
let cid = ConnectionId::read_from(mem, connection_id)?;
1221+
let length = env
1222+
.instance_env
1223+
.tx
1224+
.get()
1225+
.unwrap()
1226+
.get_jwt_payload(cid)?
1227+
.map(|p| p.len() as u32)
1228+
.unwrap_or(0u32);
1229+
length.write_to(mem, out_ptr)?;
1230+
Ok(())
1231+
})
1232+
}
1233+
1234+
pub fn get_jwt(
1235+
caller: Caller<'_, Self>,
1236+
connection_id: WasmPtr<ConnectionId>,
1237+
target_ptr: WasmPtr<u8>,
1238+
target_ptr_len: WasmPtr<u32>,
1239+
) -> RtResult<()> {
1240+
log::info!("Calling get_jwt");
1241+
Self::with_span(caller, AbiCall::GetJwt, |caller| {
1242+
let (mem, env) = Self::mem_env(caller);
1243+
let cid = ConnectionId::read_from(mem, connection_id)?;
1244+
let jwt = match env.instance_env.tx.get().unwrap().get_jwt_payload(cid)? {
1245+
None => {
1246+
// Consider logging here, since this should only happen during an upgrade.
1247+
0u32.write_to(mem, target_ptr_len)?;
1248+
return Ok(());
1249+
}
1250+
Some(jwt) => jwt,
1251+
};
1252+
log::info!("JWT payload found for connection ID: {:?}: {}", cid.to_hex(), jwt);
1253+
let jwt_len = jwt.len();
1254+
// Read `buffer_len`, i.e., the capacity of `buffer` pointed to by `buffer_ptr`.
1255+
let buffer_len = u32::read_from(mem, target_ptr_len)?;
1256+
log::info!("buffer_len: {buffer_len}");
1257+
if buffer_len < jwt_len as u32 {
1258+
return Err(anyhow::anyhow!("buffer too small to hold JWT payload"));
1259+
}
1260+
log::info!("About to write length");
1261+
// Write the length of the JWT payload to the target pointer.
1262+
(jwt_len as u32).write_to(mem, target_ptr_len)?;
1263+
log::info!("wrote length of {jwt_len}");
1264+
log::info!("Byte len {}", jwt.len());
1265+
1266+
// Write the JWT payload to the target pointer.
1267+
// Get a mutable view to the `buffer`.
1268+
let buffer = mem.deref_slice_mut(target_ptr, buffer_len)?;
1269+
buffer[..jwt_len].copy_from_slice(jwt.as_bytes());
1270+
log::info!("wrote jwt bytes to slice");
1271+
Ok(())
1272+
})
1273+
}
1274+
12111275
/// Writes the identity of the module into `out = out_ptr[..32]`.
12121276
///
12131277
/// # Traps

0 commit comments

Comments
 (0)