11mod host_component;
22
3+ use std:: collections:: HashSet ;
4+
35use anyhow:: Result ;
46use redis:: { aio:: Connection , AsyncCommands , FromRedisValue , Value } ;
57use spin_core:: { async_trait, wasmtime:: component:: Resource } ;
8+ use spin_locked_app:: MetadataKey ;
69use spin_world:: v1:: redis:: { self as v1, RedisParameter , RedisResult } ;
710use spin_world:: v2:: redis:: { self as v2, Connection as RedisConnection , Error } ;
811
12+ pub const ALLOWED_REDIS_HOSTS_KEY : MetadataKey < Vec < String > > =
13+ MetadataKey :: new ( "allowed_redis_hosts" ) ;
14+
915pub use host_component:: OutboundRedisComponent ;
1016
1117struct RedisResults ( Vec < RedisResult > ) ;
@@ -29,22 +35,24 @@ impl FromRedisValue for RedisResults {
2935}
3036
3137pub struct OutboundRedis {
38+ allowed_hosts : HashSet < String > ,
3239 connections : table:: Table < Connection > ,
3340}
3441
3542impl Default for OutboundRedis {
3643 fn default ( ) -> Self {
3744 Self {
45+ allowed_hosts : Default :: default ( ) ,
3846 connections : table:: Table :: new ( 1024 ) ,
3947 }
4048 }
4149}
4250
43- impl v2 :: Host for OutboundRedis { }
44-
45- # [ async_trait ]
46- impl v2 :: HostConnection for OutboundRedis {
47- async fn open ( & mut self , address : String ) -> Result < Result < Resource < RedisConnection > , Error > > {
51+ impl OutboundRedis {
52+ async fn establish_connection (
53+ & mut self ,
54+ address : String ,
55+ ) -> Result < Result < Resource < RedisConnection > , Error > > {
4856 Ok ( async {
4957 let conn = redis:: Client :: open ( address. as_str ( ) )
5058 . map_err ( |_| Error :: InvalidAddress ) ?
@@ -58,6 +66,23 @@ impl v2::HostConnection for OutboundRedis {
5866 }
5967 . await )
6068 }
69+ }
70+
71+ impl v2:: Host for OutboundRedis { }
72+
73+ #[ async_trait]
74+ impl v2:: HostConnection for OutboundRedis {
75+ async fn open ( & mut self , address : String ) -> Result < Result < Resource < RedisConnection > , Error > > {
76+ if !self . allowed_hosts . contains ( & address) {
77+ terminal:: warn!(
78+ "A component tried to make a HTTP request to non-allowed address '{address}'."
79+ ) ;
80+ eprintln ! ( "To allow requests, add 'allowed_redis_hosts = [\" {address}\" ]' to the manifest component section." ) ;
81+ return Ok ( Err ( Error :: InvalidAddress ) ) ;
82+ }
83+
84+ self . establish_connection ( address) . await
85+ }
6186
6287 async fn publish (
6388 & mut self ,
@@ -214,7 +239,7 @@ fn other_error(e: impl std::fmt::Display) -> Error {
214239/// Delegate a function call to the v2::HostConnection implementation
215240macro_rules! delegate {
216241 ( $self: ident. $name: ident( $address: expr, $( $arg: expr) ,* ) ) => { {
217- let connection = match < Self as v2 :: HostConnection > :: open ( $self, $address) . await ? {
242+ let connection = match $self. establish_connection ( $address) . await ? {
218243 Ok ( c) => c,
219244 Err ( _) => return Ok ( Err ( v1:: Error :: Error ) ) ,
220245 } ;
0 commit comments