@@ -294,7 +294,7 @@ impl UnitPermission {
294
294
/// A normalized environment variable name. On Windows this will
295
295
/// be uppercase and on other platforms it will stay as-is.
296
296
#[ derive( Clone , Eq , PartialEq , Hash , Debug ) ]
297
- struct EnvVarName {
297
+ pub struct EnvVarName {
298
298
inner : String ,
299
299
}
300
300
@@ -1114,15 +1114,37 @@ impl ImportDescriptor {
1114
1114
pub struct EnvDescriptorParseError ;
1115
1115
1116
1116
#[ derive( Clone , Eq , PartialEq , Hash , Debug ) ]
1117
- pub struct EnvDescriptor ( EnvVarName ) ;
1117
+ pub enum EnvDescriptor {
1118
+ Name ( EnvVarName ) ,
1119
+ PrefixPattern ( EnvVarName ) ,
1120
+ }
1118
1121
1119
1122
impl EnvDescriptor {
1120
1123
pub fn new ( env : impl AsRef < str > ) -> Self {
1121
- Self ( EnvVarName :: new ( env) )
1124
+ if let Some ( prefix_pattern) = env. as_ref ( ) . strip_suffix ( '*' ) {
1125
+ Self :: PrefixPattern ( EnvVarName :: new ( prefix_pattern) )
1126
+ } else {
1127
+ Self :: Name ( EnvVarName :: new ( env) )
1128
+ }
1129
+ }
1130
+ }
1131
+
1132
+ #[ derive( Clone , Eq , PartialEq , Hash , Debug ) ]
1133
+ enum EnvQueryDescriptorInner {
1134
+ Name ( EnvVarName ) ,
1135
+ PrefixPattern ( EnvVarName ) ,
1136
+ }
1137
+
1138
+ #[ derive( Clone , Eq , PartialEq , Hash , Debug ) ]
1139
+ pub struct EnvQueryDescriptor ( EnvQueryDescriptorInner ) ;
1140
+
1141
+ impl EnvQueryDescriptor {
1142
+ pub fn new ( env : impl AsRef < str > ) -> Self {
1143
+ Self ( EnvQueryDescriptorInner :: Name ( EnvVarName :: new ( env) ) )
1122
1144
}
1123
1145
}
1124
1146
1125
- impl QueryDescriptor for EnvDescriptor {
1147
+ impl QueryDescriptor for EnvQueryDescriptor {
1126
1148
type AllowDesc = EnvDescriptor ;
1127
1149
type DenyDesc = EnvDescriptor ;
1128
1150
@@ -1131,19 +1153,45 @@ impl QueryDescriptor for EnvDescriptor {
1131
1153
}
1132
1154
1133
1155
fn display_name ( & self ) -> Cow < str > {
1134
- Cow :: from ( self . 0 . as_ref ( ) )
1156
+ Cow :: from ( match & self . 0 {
1157
+ EnvQueryDescriptorInner :: Name ( env_var_name) => env_var_name. as_ref ( ) ,
1158
+ EnvQueryDescriptorInner :: PrefixPattern ( env_var_name) => {
1159
+ env_var_name. as_ref ( )
1160
+ }
1161
+ } )
1135
1162
}
1136
1163
1137
1164
fn from_allow ( allow : & Self :: AllowDesc ) -> Self {
1138
- allow. clone ( )
1165
+ match allow {
1166
+ Self :: AllowDesc :: Name ( s) => {
1167
+ Self ( EnvQueryDescriptorInner :: Name ( s. clone ( ) ) )
1168
+ }
1169
+ Self :: AllowDesc :: PrefixPattern ( s) => {
1170
+ Self ( EnvQueryDescriptorInner :: PrefixPattern ( s. clone ( ) ) )
1171
+ }
1172
+ }
1139
1173
}
1140
1174
1141
1175
fn as_allow ( & self ) -> Option < Self :: AllowDesc > {
1142
- Some ( self . clone ( ) )
1176
+ Some ( match & self . 0 {
1177
+ EnvQueryDescriptorInner :: Name ( env_var_name) => {
1178
+ Self :: AllowDesc :: Name ( env_var_name. clone ( ) )
1179
+ }
1180
+ EnvQueryDescriptorInner :: PrefixPattern ( env_var_name) => {
1181
+ Self :: AllowDesc :: PrefixPattern ( env_var_name. clone ( ) )
1182
+ }
1183
+ } )
1143
1184
}
1144
1185
1145
1186
fn as_deny ( & self ) -> Self :: DenyDesc {
1146
- self . clone ( )
1187
+ match & self . 0 {
1188
+ EnvQueryDescriptorInner :: Name ( env_var_name) => {
1189
+ Self :: DenyDesc :: Name ( env_var_name. clone ( ) )
1190
+ }
1191
+ EnvQueryDescriptorInner :: PrefixPattern ( env_var_name) => {
1192
+ Self :: DenyDesc :: PrefixPattern ( env_var_name. clone ( ) )
1193
+ }
1194
+ }
1147
1195
}
1148
1196
1149
1197
fn check_in_permission (
@@ -1156,29 +1204,94 @@ impl QueryDescriptor for EnvDescriptor {
1156
1204
}
1157
1205
1158
1206
fn matches_allow ( & self , other : & Self :: AllowDesc ) -> bool {
1159
- self == other
1207
+ match other {
1208
+ Self :: AllowDesc :: Name ( n) => match & self . 0 {
1209
+ EnvQueryDescriptorInner :: Name ( env_var_name) => n == env_var_name,
1210
+ EnvQueryDescriptorInner :: PrefixPattern ( env_var_name) => {
1211
+ env_var_name. as_ref ( ) . starts_with ( n. as_ref ( ) )
1212
+ }
1213
+ } ,
1214
+ Self :: AllowDesc :: PrefixPattern ( p) => match & self . 0 {
1215
+ EnvQueryDescriptorInner :: Name ( env_var_name) => {
1216
+ env_var_name. as_ref ( ) . starts_with ( p. as_ref ( ) )
1217
+ }
1218
+ EnvQueryDescriptorInner :: PrefixPattern ( env_var_name) => {
1219
+ env_var_name. as_ref ( ) . starts_with ( p. as_ref ( ) )
1220
+ }
1221
+ } ,
1222
+ }
1160
1223
}
1161
1224
1162
1225
fn matches_deny ( & self , other : & Self :: DenyDesc ) -> bool {
1163
- self == other
1226
+ match other {
1227
+ Self :: AllowDesc :: Name ( n) => match & self . 0 {
1228
+ EnvQueryDescriptorInner :: Name ( env_var_name) => n == env_var_name,
1229
+ EnvQueryDescriptorInner :: PrefixPattern ( env_var_name) => {
1230
+ env_var_name. as_ref ( ) . starts_with ( n. as_ref ( ) )
1231
+ }
1232
+ } ,
1233
+ Self :: AllowDesc :: PrefixPattern ( p) => match & self . 0 {
1234
+ EnvQueryDescriptorInner :: Name ( env_var_name) => {
1235
+ env_var_name. as_ref ( ) . starts_with ( p. as_ref ( ) )
1236
+ }
1237
+ EnvQueryDescriptorInner :: PrefixPattern ( env_var_name) => {
1238
+ p == env_var_name
1239
+ }
1240
+ } ,
1241
+ }
1164
1242
}
1165
1243
1166
1244
fn revokes ( & self , other : & Self :: AllowDesc ) -> bool {
1167
- self == other
1245
+ match other {
1246
+ Self :: AllowDesc :: Name ( n) => match & self . 0 {
1247
+ EnvQueryDescriptorInner :: Name ( env_var_name) => n == env_var_name,
1248
+ EnvQueryDescriptorInner :: PrefixPattern ( env_var_name) => {
1249
+ env_var_name. as_ref ( ) . starts_with ( n. as_ref ( ) )
1250
+ }
1251
+ } ,
1252
+ Self :: AllowDesc :: PrefixPattern ( p) => match & self . 0 {
1253
+ EnvQueryDescriptorInner :: Name ( env_var_name) => {
1254
+ env_var_name. as_ref ( ) . starts_with ( p. as_ref ( ) )
1255
+ }
1256
+ EnvQueryDescriptorInner :: PrefixPattern ( env_var_name) => {
1257
+ p == env_var_name
1258
+ }
1259
+ } ,
1260
+ }
1168
1261
}
1169
1262
1170
1263
fn stronger_than_deny ( & self , other : & Self :: DenyDesc ) -> bool {
1171
- self == other
1264
+ match other {
1265
+ Self :: AllowDesc :: Name ( n) => match & self . 0 {
1266
+ EnvQueryDescriptorInner :: Name ( env_var_name) => n == env_var_name,
1267
+ EnvQueryDescriptorInner :: PrefixPattern ( env_var_name) => {
1268
+ env_var_name. as_ref ( ) . starts_with ( n. as_ref ( ) )
1269
+ }
1270
+ } ,
1271
+ Self :: AllowDesc :: PrefixPattern ( p) => match & self . 0 {
1272
+ EnvQueryDescriptorInner :: Name ( env_var_name) => {
1273
+ env_var_name. as_ref ( ) . starts_with ( p. as_ref ( ) )
1274
+ }
1275
+ EnvQueryDescriptorInner :: PrefixPattern ( env_var_name) => {
1276
+ p == env_var_name
1277
+ }
1278
+ } ,
1279
+ }
1172
1280
}
1173
1281
1174
1282
fn overlaps_deny ( & self , _other : & Self :: DenyDesc ) -> bool {
1175
1283
false
1176
1284
}
1177
1285
}
1178
1286
1179
- impl AsRef < str > for EnvDescriptor {
1287
+ impl AsRef < str > for EnvQueryDescriptor {
1180
1288
fn as_ref ( & self ) -> & str {
1181
- self . 0 . as_ref ( )
1289
+ match & self . 0 {
1290
+ EnvQueryDescriptorInner :: Name ( env_var_name) => env_var_name. as_ref ( ) ,
1291
+ EnvQueryDescriptorInner :: PrefixPattern ( env_var_name) => {
1292
+ env_var_name. as_ref ( )
1293
+ }
1294
+ }
1182
1295
}
1183
1296
}
1184
1297
@@ -1749,20 +1862,20 @@ impl UnaryPermission<ImportDescriptor> {
1749
1862
}
1750
1863
}
1751
1864
1752
- impl UnaryPermission < EnvDescriptor > {
1865
+ impl UnaryPermission < EnvQueryDescriptor > {
1753
1866
pub fn query ( & self , env : Option < & str > ) -> PermissionState {
1754
1867
self . query_desc (
1755
- env. map ( EnvDescriptor :: new) . as_ref ( ) ,
1868
+ env. map ( EnvQueryDescriptor :: new) . as_ref ( ) ,
1756
1869
AllowPartial :: TreatAsPartialGranted ,
1757
1870
)
1758
1871
}
1759
1872
1760
1873
pub fn request ( & mut self , env : Option < & str > ) -> PermissionState {
1761
- self . request_desc ( env. map ( EnvDescriptor :: new) . as_ref ( ) )
1874
+ self . request_desc ( env. map ( EnvQueryDescriptor :: new) . as_ref ( ) )
1762
1875
}
1763
1876
1764
1877
pub fn revoke ( & mut self , env : Option < & str > ) -> PermissionState {
1765
- self . revoke_desc ( env. map ( EnvDescriptor :: new) . as_ref ( ) )
1878
+ self . revoke_desc ( env. map ( EnvQueryDescriptor :: new) . as_ref ( ) )
1766
1879
}
1767
1880
1768
1881
pub fn check (
@@ -1771,7 +1884,7 @@ impl UnaryPermission<EnvDescriptor> {
1771
1884
api_name : Option < & str > ,
1772
1885
) -> Result < ( ) , PermissionDeniedError > {
1773
1886
skip_check_if_is_permission_fully_granted ! ( self ) ;
1774
- self . check_desc ( Some ( & EnvDescriptor :: new ( env) ) , false , api_name)
1887
+ self . check_desc ( Some ( & EnvQueryDescriptor :: new ( env) ) , false , api_name)
1775
1888
}
1776
1889
1777
1890
pub fn check_all ( & mut self ) -> Result < ( ) , PermissionDeniedError > {
@@ -1905,7 +2018,7 @@ pub struct Permissions {
1905
2018
pub read : UnaryPermission < ReadQueryDescriptor > ,
1906
2019
pub write : UnaryPermission < WriteQueryDescriptor > ,
1907
2020
pub net : UnaryPermission < NetDescriptor > ,
1908
- pub env : UnaryPermission < EnvDescriptor > ,
2021
+ pub env : UnaryPermission < EnvQueryDescriptor > ,
1909
2022
pub sys : UnaryPermission < SysDescriptor > ,
1910
2023
pub run : UnaryPermission < RunQueryDescriptor > ,
1911
2024
pub ffi : UnaryPermission < FfiQueryDescriptor > ,
@@ -4564,6 +4677,56 @@ mod tests {
4564
4677
assert_eq ! ( perms. env. revoke( Some ( "HomE" ) ) , PermissionState :: Prompt ) ;
4565
4678
}
4566
4679
4680
+ #[ test]
4681
+ fn test_env_wildcards ( ) {
4682
+ set_prompter ( Box :: new ( TestPrompter ) ) ;
4683
+ let _prompt_value = PERMISSION_PROMPT_STUB_VALUE_SETTER . lock ( ) ;
4684
+ let mut perms = Permissions :: allow_all ( ) ;
4685
+ perms. env = UnaryPermission {
4686
+ granted_global : false ,
4687
+ ..Permissions :: new_unary (
4688
+ Some ( HashSet :: from ( [ EnvDescriptor :: new ( "HOME_*" ) ] ) ) ,
4689
+ None ,
4690
+ false ,
4691
+ )
4692
+ } ;
4693
+ assert_eq ! ( perms. env. query( Some ( "HOME" ) ) , PermissionState :: Prompt ) ;
4694
+ assert_eq ! ( perms. env. query( Some ( "HOME_" ) ) , PermissionState :: Granted ) ;
4695
+ assert_eq ! ( perms. env. query( Some ( "HOME_TEST" ) ) , PermissionState :: Granted ) ;
4696
+
4697
+ // assert no privilege escalation
4698
+ let parser = TestPermissionDescriptorParser ;
4699
+ assert ! ( perms
4700
+ . env
4701
+ . create_child_permissions(
4702
+ ChildUnaryPermissionArg :: GrantedList ( vec![ "HOME_SUB" . to_string( ) ] ) ,
4703
+ |value| parser. parse_env_descriptor( value) . map( Some ) ,
4704
+ )
4705
+ . is_ok( ) ) ;
4706
+ assert ! ( perms
4707
+ . env
4708
+ . create_child_permissions(
4709
+ ChildUnaryPermissionArg :: GrantedList ( vec![ "HOME*" . to_string( ) ] ) ,
4710
+ |value| parser. parse_env_descriptor( value) . map( Some ) ,
4711
+ )
4712
+ . is_err( ) ) ;
4713
+ assert ! ( perms
4714
+ . env
4715
+ . create_child_permissions(
4716
+ ChildUnaryPermissionArg :: GrantedList ( vec![ "OUTSIDE" . to_string( ) ] ) ,
4717
+ |value| parser. parse_env_descriptor( value) . map( Some ) ,
4718
+ )
4719
+ . is_err( ) ) ;
4720
+ assert ! ( perms
4721
+ . env
4722
+ . create_child_permissions(
4723
+ // ok because this is a subset of HOME_*
4724
+ ChildUnaryPermissionArg :: GrantedList ( vec![ "HOME_S*" . to_string( ) ] ) ,
4725
+ |value| parser. parse_env_descriptor( value) . map( Some ) ,
4726
+ )
4727
+ . is_ok( ) ) ;
4728
+ }
4729
+
4567
4730
#[ test]
4568
4731
fn test_check_partial_denied ( ) {
4569
4732
let parser = TestPermissionDescriptorParser ;
0 commit comments