1- use anyhow:: Result ;
1+ use anyhow:: { Context , Result } ;
22use mysql_async:: { consts:: ColumnType , from_value_opt, prelude:: * , Opts , OptsBuilder , SslOpts } ;
3+ use spin_app:: DynamicHostComponent ;
34use spin_core:: wasmtime:: component:: Resource ;
45use spin_core:: { async_trait, HostComponent } ;
56use spin_world:: v1:: mysql as v1;
@@ -12,6 +13,7 @@ use url::Url;
1213/// A simple implementation to support outbound mysql connection
1314#[ derive( Default ) ]
1415pub struct OutboundMysql {
16+ allowed_hosts : Option < spin_outbound_networking:: AllowedHosts > ,
1517 pub connections : table:: Table < mysql_async:: Conn > ,
1618}
1719
@@ -24,6 +26,10 @@ impl OutboundMysql {
2426 . get_mut ( connection. rep ( ) )
2527 . ok_or_else ( || v2:: Error :: ConnectionFailed ( "no connection found" . into ( ) ) )
2628 }
29+
30+ fn is_address_allowed ( & self , address : & str , default : bool ) -> bool {
31+ spin_outbound_networking:: check_address ( address, "mysql" , & self . allowed_hosts , default)
32+ }
2733}
2834
2935impl HostComponent for OutboundMysql {
@@ -42,11 +48,33 @@ impl HostComponent for OutboundMysql {
4248 }
4349}
4450
51+ impl DynamicHostComponent for OutboundMysql {
52+ fn update_data (
53+ & self ,
54+ data : & mut Self :: Data ,
55+ component : & spin_app:: AppComponent ,
56+ ) -> anyhow:: Result < ( ) > {
57+ let hosts = component
58+ . get_metadata ( spin_outbound_networking:: ALLOWED_HOSTS_KEY ) ?
59+ . unwrap_or_default ( ) ;
60+ data. allowed_hosts = hosts
61+ . map ( |h| spin_outbound_networking:: AllowedHosts :: parse ( & h[ ..] ) )
62+ . transpose ( )
63+ . context ( "`allowed_outbound_hosts` contained an invalid url" ) ?;
64+ Ok ( ( ) )
65+ }
66+ }
67+
4568impl v2:: Host for OutboundMysql { }
4669
4770#[ async_trait]
4871impl v2:: HostConnection for OutboundMysql {
4972 async fn open ( & mut self , address : String ) -> Result < Result < Resource < Connection > , v2:: Error > > {
73+ if !self . is_address_allowed ( & address, false ) {
74+ return Ok ( Err ( v2:: Error :: ConnectionFailed ( format ! (
75+ "address {address} is not permitted"
76+ ) ) ) ) ;
77+ }
5078 Ok ( async {
5179 self . connections
5280 . push (
@@ -125,6 +153,11 @@ impl v2::HostConnection for OutboundMysql {
125153/// Delegate a function call to the v2::HostConnection implementation
126154macro_rules! delegate {
127155 ( $self: ident. $name: ident( $address: expr, $( $arg: expr) ,* ) ) => { {
156+ if !$self. is_address_allowed( & $address, true ) {
157+ return Ok ( Err ( v1:: MysqlError :: ConnectionFailed ( format!(
158+ "address {} is not permitted" , $address
159+ ) ) ) ) ;
160+ }
128161 let connection = match <Self as v2:: HostConnection >:: open( $self, $address) . await ? {
129162 Ok ( c) => c,
130163 Err ( e) => return Ok ( Err ( e. into( ) ) ) ,
0 commit comments