@@ -100,7 +100,7 @@ impl<F: Fn(&str, &str) + Send + Sync> DisallowedHostHandler for F {
100
100
}
101
101
}
102
102
103
- /// An address is a url-like string that contains a host, a port, and an optional scheme
103
+ /// Represents a single `allowed_outbound_hosts` item.
104
104
#[ derive( Eq , Debug , Clone ) ]
105
105
pub struct AllowedHostConfig {
106
106
original : String ,
@@ -110,10 +110,7 @@ pub struct AllowedHostConfig {
110
110
}
111
111
112
112
impl AllowedHostConfig {
113
- /// Try to parse the address.
114
- ///
115
- /// If the parsing fails, the address is prepended with the scheme and parsing
116
- /// is tried again.
113
+ /// Parses the given string as an `allowed_hosts_config` item.
117
114
pub fn parse ( url : impl Into < String > ) -> anyhow:: Result < Self > {
118
115
let original = url. into ( ) ;
119
116
let url = original. trim ( ) ;
@@ -154,12 +151,15 @@ impl AllowedHostConfig {
154
151
& self . port
155
152
}
156
153
154
+ /// Returns true if the given URL is allowed.
157
155
fn allows ( & self , url : & OutboundUrl ) -> bool {
158
156
self . scheme . allows ( & url. scheme )
159
157
&& self . host . allows ( & url. host )
160
158
&& self . port . allows ( url. port , & url. scheme )
161
159
}
162
160
161
+ /// Returns true if relative ("self") requests to any of the given schemes
162
+ /// are allowed.
163
163
fn allows_relative ( & self , schemes : & [ & str ] ) -> bool {
164
164
schemes. iter ( ) . any ( |s| self . scheme . allows ( s) ) && self . host . allows_relative ( )
165
165
}
@@ -177,34 +177,39 @@ impl std::fmt::Display for AllowedHostConfig {
177
177
}
178
178
}
179
179
180
+ /// Represents the scheme part of an allowed_outbound_hosts item.
180
181
#[ derive( PartialEq , Eq , Debug , Clone ) ]
181
182
pub enum SchemeConfig {
183
+ /// Any scheme is allowed: `*://`
182
184
Any ,
185
+ /// Any scheme is allowed: `*://`
183
186
List ( Vec < String > ) ,
184
187
}
185
188
186
189
impl SchemeConfig {
190
+ /// Parses the scheme part of an allowed_outbound_hosts item.
187
191
fn parse ( scheme : & str ) -> anyhow:: Result < Self > {
188
192
if scheme == "*" {
189
193
return Ok ( Self :: Any ) ;
190
194
}
191
195
192
196
if scheme. starts_with ( '{' ) {
193
- // TODO:
194
- bail ! ( "scheme lists are not yet supported" )
197
+ anyhow:: bail!( "scheme lists are not supported" )
195
198
}
196
199
197
200
if scheme. chars ( ) . any ( |c| !c. is_alphabetic ( ) ) {
198
- anyhow:: bail!( " scheme {scheme:?} contains non alphabetic character" ) ;
201
+ anyhow:: bail!( "scheme {scheme:?} contains non alphabetic character" ) ;
199
202
}
200
203
201
204
Ok ( Self :: List ( vec ! [ scheme. into( ) ] ) )
202
205
}
203
206
207
+ /// Returns true if any scheme is allowed (i.e. `*://`).
204
208
pub fn allows_any ( & self ) -> bool {
205
209
matches ! ( self , Self :: Any )
206
210
}
207
211
212
+ /// Returns true if the given scheme is allowed.
208
213
fn allows ( & self , scheme : & str ) -> bool {
209
214
match self {
210
215
SchemeConfig :: Any => true ,
@@ -213,6 +218,7 @@ impl SchemeConfig {
213
218
}
214
219
}
215
220
221
+ /// Represents the host part of an allowed_outbound_hosts item.
216
222
#[ derive( Debug , PartialEq , Eq , Clone ) ]
217
223
pub enum HostConfig {
218
224
Any ,
@@ -223,6 +229,7 @@ pub enum HostConfig {
223
229
}
224
230
225
231
impl HostConfig {
232
+ /// Parses the host part of an allowed_outbound_hosts item.
226
233
fn parse ( mut host : & str ) -> anyhow:: Result < Self > {
227
234
host = host. trim ( ) ;
228
235
if host == "*" {
@@ -263,6 +270,7 @@ impl HostConfig {
263
270
Ok ( Self :: List ( vec ! [ host. into( ) ] ) )
264
271
}
265
272
273
+ /// Returns true if the given host is allowed.
266
274
fn allows ( & self , host : & str ) -> bool {
267
275
match self {
268
276
HostConfig :: Any => true ,
@@ -278,18 +286,21 @@ impl HostConfig {
278
286
}
279
287
}
280
288
289
+ /// Returns true if relative ("self") requests are allowed.
281
290
fn allows_relative ( & self ) -> bool {
282
291
matches ! ( self , Self :: Any | Self :: ToSelf )
283
292
}
284
293
}
285
294
295
+ /// Represents the port part of an allowed_outbound_hosts item.
286
296
#[ derive( Debug , PartialEq , Eq , Clone ) ]
287
297
pub enum PortConfig {
288
298
Any ,
289
299
List ( Vec < IndividualPortConfig > ) ,
290
300
}
291
301
292
302
impl PortConfig {
303
+ /// Parses the port part of an allowed_outbound_hosts item.
293
304
fn parse ( port : & str , scheme : & str ) -> anyhow:: Result < PortConfig > {
294
305
if port. is_empty ( ) {
295
306
return well_known_port ( scheme)
@@ -310,6 +321,7 @@ impl PortConfig {
310
321
Ok ( Self :: List ( vec ! [ port] ) )
311
322
}
312
323
324
+ /// Returns true if the given port (or scheme-default port) is allowed.
313
325
fn allows ( & self , port : Option < u16 > , scheme : & str ) -> bool {
314
326
match self {
315
327
PortConfig :: Any => true ,
@@ -324,13 +336,15 @@ impl PortConfig {
324
336
}
325
337
}
326
338
339
+ /// Represents a single port specifier in an allowed_outbound_hosts item.
327
340
#[ derive( Debug , PartialEq , Eq , Clone ) ]
328
341
pub enum IndividualPortConfig {
329
342
Port ( u16 ) ,
330
343
Range ( Range < u16 > ) ,
331
344
}
332
345
333
346
impl IndividualPortConfig {
347
+ /// Parses the a single port specifier in an allowed_outbound_hosts item.
334
348
fn parse ( port : & str ) -> anyhow:: Result < Self > {
335
349
if let Some ( ( start, end) ) = port. split_once ( ".." ) {
336
350
let start = start
@@ -346,6 +360,7 @@ impl IndividualPortConfig {
346
360
} ) ?) )
347
361
}
348
362
363
+ /// Returns true if the given port is allowed.
349
364
fn allows ( & self , port : u16 ) -> bool {
350
365
match self {
351
366
IndividualPortConfig :: Port ( p) => p == & port,
@@ -354,6 +369,7 @@ impl IndividualPortConfig {
354
369
}
355
370
}
356
371
372
+ /// Returns a well-known default port for the given URL scheme.
357
373
fn well_known_port ( scheme : & str ) -> Option < u16 > {
358
374
match scheme {
359
375
"postgres" => Some ( 5432 ) ,
@@ -366,12 +382,15 @@ fn well_known_port(scheme: &str) -> Option<u16> {
366
382
}
367
383
}
368
384
385
+ /// Holds a single allowed_outbound_hosts item, either parsed or as an
386
+ /// unresolved template.
369
387
enum PartialAllowedHostConfig {
370
388
Exact ( AllowedHostConfig ) ,
371
389
Unresolved ( spin_expressions:: Template ) ,
372
390
}
373
391
374
392
impl PartialAllowedHostConfig {
393
+ /// Returns this config, resolving any template with the given resolver.
375
394
fn resolve (
376
395
self ,
377
396
resolver : & spin_expressions:: PreparedResolver ,
@@ -383,13 +402,16 @@ impl PartialAllowedHostConfig {
383
402
}
384
403
}
385
404
405
+ /// Represents an allowed_outbound_hosts config.
386
406
#[ derive( PartialEq , Eq , Debug , Clone ) ]
387
407
pub enum AllowedHostsConfig {
388
408
All ,
389
409
SpecificHosts ( Vec < AllowedHostConfig > ) ,
390
410
}
391
411
392
412
impl AllowedHostsConfig {
413
+ /// Parses the given allowed_outbound_hosts values, resolving any templates
414
+ /// with the given resolver.
393
415
pub fn parse < S : AsRef < str > > (
394
416
hosts : & [ S ] ,
395
417
resolver : & spin_expressions:: PreparedResolver ,
@@ -402,13 +424,15 @@ impl AllowedHostsConfig {
402
424
Ok ( Self :: SpecificHosts ( allowed) )
403
425
}
404
426
427
+ /// Validate the given allowed_outbound_hosts values. Templated values are
428
+ /// only validated against template syntax.
405
429
pub fn validate < S : AsRef < str > > ( hosts : & [ S ] ) -> anyhow:: Result < ( ) > {
406
430
_ = Self :: parse_partial ( hosts) ?;
407
431
Ok ( ( ) )
408
432
}
409
433
410
- // Parses literals but defers templates. This is pulled out so that `validate`
411
- // doesn't have to deal with resolving templates .
434
+ /// Parse the given allowed_outbound_hosts values with deferred parsing of
435
+ /// templated values .
412
436
fn parse_partial < S : AsRef < str > > ( hosts : & [ S ] ) -> anyhow:: Result < Vec < PartialAllowedHostConfig > > {
413
437
if hosts. len ( ) == 1 && hosts[ 0 ] . as_ref ( ) == "insecure:allow-all" {
414
438
bail ! ( "'insecure:allow-all' is not allowed - use '*://*:*' instead if you really want to allow all outbound traffic'" )
@@ -427,14 +451,16 @@ impl AllowedHostsConfig {
427
451
Ok ( allowed)
428
452
}
429
453
430
- /// Determine if the supplied url is allowed
454
+ /// Returns true if the given url is allowed.
431
455
pub fn allows ( & self , url : & OutboundUrl ) -> bool {
432
456
match self {
433
457
AllowedHostsConfig :: All => true ,
434
458
AllowedHostsConfig :: SpecificHosts ( hosts) => hosts. iter ( ) . any ( |h| h. allows ( url) ) ,
435
459
}
436
460
}
437
461
462
+ /// Returns true if relative ("self") requests to any of the given schemes
463
+ /// are allowed.
438
464
pub fn allows_relative_url ( & self , schemes : & [ & str ] ) -> bool {
439
465
match self {
440
466
AllowedHostsConfig :: All => true ,
@@ -461,7 +487,7 @@ pub struct OutboundUrl {
461
487
}
462
488
463
489
impl OutboundUrl {
464
- /// Parse a URL.
490
+ /// Parses a URL.
465
491
///
466
492
/// If parsing `url` fails, `{scheme}://` is prepended to `url` and parsing is tried again.
467
493
pub fn parse ( url : impl Into < String > , scheme : & str ) -> anyhow:: Result < Self > {
0 commit comments