@@ -11,8 +11,11 @@ use wasmparser::names::KebabStr;
1111#[ derive( Default , Deserialize ) ]
1212pub struct AuthorizedKeyPolicy {
1313 #[ serde( skip) ]
14- keys : HashSet < KeyID > ,
14+ superuser_keys : HashSet < KeyID > ,
15+ #[ serde( default ) ]
1516 namespace_keys : HashMap < String , HashSet < KeyID > > ,
17+ #[ serde( default ) ]
18+ package_keys : HashMap < PackageId , HashSet < KeyID > > ,
1619}
1720
1821impl AuthorizedKeyPolicy {
@@ -24,8 +27,8 @@ impl AuthorizedKeyPolicy {
2427 }
2528
2629 /// Sets an authorized key for publishing to any namespace.
27- pub fn with_key ( mut self , key : KeyID ) -> Self {
28- self . keys . insert ( key) ;
30+ pub fn with_superuser_key ( mut self , key : KeyID ) -> Self {
31+ self . superuser_keys . insert ( key) ;
2932 self
3033 }
3134
@@ -42,6 +45,33 @@ impl AuthorizedKeyPolicy {
4245 . insert ( key) ;
4346 Ok ( self )
4447 }
48+
49+ pub fn with_package_key ( mut self , package_id : impl Into < String > , key : KeyID ) -> Result < Self > {
50+ let package_id = PackageId :: new ( package_id) ?;
51+ self . package_keys . entry ( package_id) . or_default ( ) . insert ( key) ;
52+ Ok ( self )
53+ }
54+
55+ pub fn key_authorized_for_package ( & self , key : & KeyID , package : & PackageId ) -> bool {
56+ if self . superuser_keys . contains ( key) {
57+ return true ;
58+ }
59+
60+ let namespace_keys = self . namespace_keys . get ( package. namespace ( ) ) ;
61+ if namespace_keys
62+ . map ( |keys| keys. contains ( key) )
63+ . unwrap_or ( false )
64+ {
65+ return true ;
66+ }
67+
68+ let package_keys = self . package_keys . get ( package) ;
69+ if package_keys. map ( |keys| keys. contains ( key) ) . unwrap_or ( false ) {
70+ return true ;
71+ }
72+
73+ false
74+ }
4575}
4676
4777impl RecordPolicy for AuthorizedKeyPolicy {
@@ -50,18 +80,51 @@ impl RecordPolicy for AuthorizedKeyPolicy {
5080 id : & PackageId ,
5181 record : & ProtoEnvelope < PackageRecord > ,
5282 ) -> RecordPolicyResult < ( ) > {
53- if !self . keys . contains ( record. key_id ( ) )
54- && !self
55- . namespace_keys
56- . get ( id. namespace ( ) )
57- . map ( |keys| keys. contains ( record. key_id ( ) ) )
58- . unwrap_or ( false )
59- {
83+ let key = record. key_id ( ) ;
84+ if !self . key_authorized_for_package ( key, id) {
6085 return Err ( RecordPolicyError :: Unauthorized ( format ! (
6186 "key id `{key}` is not authorized to publish to package `{id}`" ,
62- key = record. key_id( )
6387 ) ) ) ;
6488 }
89+ Ok ( ( ) )
90+ }
91+ }
92+
93+ #[ cfg( test) ]
94+ mod tests {
95+ use super :: * ;
96+
97+ #[ test]
98+ fn test_key_authorized_for_package ( ) -> Result < ( ) > {
99+ let super_key = KeyID :: from ( "super-key" . to_string ( ) ) ;
100+ let namespace_key = KeyID :: from ( "namespace-key" . to_string ( ) ) ;
101+ let package_key = KeyID :: from ( "package-key" . to_string ( ) ) ;
102+ let other_key = KeyID :: from ( "other-key" . to_string ( ) ) ;
103+
104+ let policy = AuthorizedKeyPolicy :: new ( )
105+ . with_superuser_key ( super_key. clone ( ) )
106+ . with_namespace_key ( "my-namespace" , namespace_key. clone ( ) ) ?
107+ . with_package_key ( "my-namespace:my-package" , package_key. clone ( ) ) ?;
108+
109+ let my_package: PackageId = "my-namespace:my-package" . parse ( ) ?;
110+ let my_namespace_other_package: PackageId = "my-namespace:other-package" . parse ( ) ?;
111+ let other_namespace: PackageId = "other-namespace:any-package" . parse ( ) ?;
112+
113+ assert ! ( policy. key_authorized_for_package( & super_key, & my_package) ) ;
114+ assert ! ( policy. key_authorized_for_package( & super_key, & my_namespace_other_package) ) ;
115+ assert ! ( policy. key_authorized_for_package( & super_key, & other_namespace) ) ;
116+
117+ assert ! ( policy. key_authorized_for_package( & namespace_key, & my_package) ) ;
118+ assert ! ( policy. key_authorized_for_package( & namespace_key, & my_namespace_other_package) ) ;
119+ assert ! ( !policy. key_authorized_for_package( & namespace_key, & other_namespace) ) ;
120+
121+ assert ! ( policy. key_authorized_for_package( & package_key, & my_package) ) ;
122+ assert ! ( !policy. key_authorized_for_package( & package_key, & my_namespace_other_package) ) ;
123+ assert ! ( !policy. key_authorized_for_package( & package_key, & other_namespace) ) ;
124+
125+ assert ! ( !policy. key_authorized_for_package( & other_key, & my_package) ) ;
126+ assert ! ( !policy. key_authorized_for_package( & other_key, & my_namespace_other_package) ) ;
127+ assert ! ( !policy. key_authorized_for_package( & other_key, & other_namespace) ) ;
65128
66129 Ok ( ( ) )
67130 }
0 commit comments