@@ -98,7 +98,7 @@ struct CertRevRecordAttachment {
98
98
fn update_intermediates ( int_dir : & Path ) -> Result < ( ) , CRLiteDBError > {
99
99
let intermediates_path = int_dir. join ( "crlite.intermediates" ) ;
100
100
101
- info ! ( "Fetching {}" , ICA_LIST_URL ) ;
101
+ debug ! ( "Fetching {}" , ICA_LIST_URL ) ;
102
102
let intermediates_bytes = & reqwest:: blocking:: get ( ICA_LIST_URL )
103
103
. map_err ( |_| CRLiteDBError :: from ( "could not fetch CCADB report" ) ) ?
104
104
. bytes ( )
@@ -120,7 +120,7 @@ fn update_db(
120
120
base_url : & str ,
121
121
channel : & CRLiteFilterChannel ,
122
122
) -> Result < ( ) , CRLiteDBError > {
123
- info ! (
123
+ debug ! (
124
124
"Fetching cert-revocations records from remote settings {}" ,
125
125
base_url
126
126
) ;
@@ -157,7 +157,7 @@ fn update_db(
157
157
if ( extension == Some ( "delta" ) || extension == Some ( "filter" ) )
158
158
&& !expected_filenames. contains ( & dir_entry. file_name ( ) )
159
159
{
160
- info ! ( "Removing {:?}" , dir_entry. file_name( ) ) ;
160
+ debug ! ( "Removing {:?}" , dir_entry. file_name( ) ) ;
161
161
let _ = std:: fs:: remove_file ( dir_entry_path) ;
162
162
}
163
163
}
@@ -169,13 +169,13 @@ fn update_db(
169
169
if path. exists ( ) {
170
170
let digest = Sha256 :: digest ( std:: fs:: read ( & path) ?) ;
171
171
if expected_digest == digest. as_slice ( ) {
172
- info ! ( "Found existing copy of {}" , filter. attachment. filename) ;
172
+ debug ! ( "Found existing copy of {}" , filter. attachment. filename) ;
173
173
continue ;
174
174
}
175
175
}
176
176
177
177
let filter_url = format ! ( "{}{}" , attachment_url, filter. attachment. location) ;
178
- info ! (
178
+ debug ! (
179
179
"Fetching {} from {}" ,
180
180
filter. attachment. filename, filter_url
181
181
) ;
@@ -210,25 +210,35 @@ fn get_sct_ids_and_timestamps(cert: &X509Certificate) -> Vec<([u8; 32], u64)> {
210
210
}
211
211
212
212
enum Filter {
213
- Clubcard ( CRLiteClubcard ) ,
213
+ Clubcard ( ( /* filename */ String , CRLiteClubcard ) ) ,
214
214
}
215
215
216
216
impl Filter {
217
- fn from_bytes ( bytes : & [ u8 ] ) -> Result < Self , CRLiteDBError > {
218
- if let Ok ( clubcard) = CRLiteClubcard :: from_bytes ( bytes) {
219
- return Ok ( Filter :: Clubcard ( clubcard) ) ;
217
+ fn from_file ( file : & PathBuf ) -> Result < Self , CRLiteDBError > {
218
+ let name = file
219
+ . file_name ( )
220
+ . and_then ( std:: ffi:: OsStr :: to_str)
221
+ . unwrap_or_default ( ) ;
222
+ if let Ok ( clubcard) = CRLiteClubcard :: from_bytes ( & std:: fs:: read ( file) ?) {
223
+ return Ok ( Filter :: Clubcard ( ( name. into ( ) , clubcard) ) ) ;
220
224
}
221
225
Err ( CRLiteDBError :: from ( "could not load filter" ) )
222
226
}
223
227
228
+ fn name ( & self ) -> & str {
229
+ match self {
230
+ Filter :: Clubcard ( ( name, _) ) => name,
231
+ }
232
+ }
233
+
224
234
fn has (
225
235
& self ,
226
236
issuer_spki_hash : & [ u8 ; 32 ] ,
227
237
serial : & [ u8 ] ,
228
238
timestamps : & [ ( [ u8 ; 32 ] , u64 ) ] ,
229
239
) -> Status {
230
240
match self {
231
- Filter :: Clubcard ( clubcard) => {
241
+ Filter :: Clubcard ( ( _ , clubcard) ) => {
232
242
let crlite_key = clubcard_crlite:: CRLiteKey :: new ( issuer_spki_hash, serial) ;
233
243
match clubcard. contains ( & crlite_key, timestamps. iter ( ) . map ( |( x, y) | ( x, * y) ) ) {
234
244
CRLiteStatus :: Good => Status :: Good ,
@@ -259,7 +269,7 @@ impl CRLiteDB {
259
269
. extension ( )
260
270
. and_then ( |os_str| os_str. to_str ( ) ) ;
261
271
if extension == Some ( "delta" ) || extension == Some ( "filter" ) {
262
- filters. push ( Filter :: from_bytes ( & std :: fs :: read ( & dir_entry_path) ? ) ?) ;
272
+ filters. push ( Filter :: from_file ( & dir_entry_path) ?) ;
263
273
if let Ok ( metadata) = std:: fs:: metadata ( & dir_entry_path) {
264
274
if let Ok ( modified) = metadata. modified ( ) {
265
275
most_recent_time = Some (
@@ -271,6 +281,10 @@ impl CRLiteDB {
271
281
}
272
282
}
273
283
284
+ // Sort the filters by name so that (when trace level output is enabled)
285
+ // individual results are sorted chronologically.
286
+ filters. sort_by_key ( |x| x. name ( ) . to_string ( ) ) ;
287
+
274
288
if filters. is_empty ( ) {
275
289
error ! ( "No CRLite filters found. All results will indicate NotCovered. Use --update to download filters." ) ;
276
290
} else if let Some ( time) = most_recent_time {
@@ -328,11 +342,13 @@ impl CRLiteDB {
328
342
329
343
let issuer_spki_hash = Sha256 :: digest ( issuer_spki) ;
330
344
for filter in & self . filters {
331
- match filter. has (
345
+ let one_filter_result = filter. has (
332
346
issuer_spki_hash. as_ref ( ) ,
333
347
serial,
334
348
& get_sct_ids_and_timestamps ( cert) ,
335
- ) {
349
+ ) ;
350
+ trace ! ( "{}: {:?}" , filter. name( ) , one_filter_result) ;
351
+ match one_filter_result {
336
352
Status :: Revoked => return Status :: Revoked ,
337
353
Status :: Good => maybe_good = true ,
338
354
Status :: NotEnrolled => covered = true ,
@@ -516,11 +532,11 @@ fn query_https_addr(
516
532
debug ! ( "Loaded certificate from {}" , host) ;
517
533
let status = db. query ( & cert) ;
518
534
match status {
519
- Status :: Expired => warn ! ( "{} {:?}" , host, status) ,
535
+ Status :: Expired => info ! ( "{} {:?}" , host, status) ,
520
536
Status :: Good => info ! ( "{} {:?}" , host, status) ,
521
- Status :: NotCovered => warn ! ( "{} {:?}" , host, status) ,
522
- Status :: NotEnrolled => warn ! ( "{} {:?}" , host, status) ,
523
- Status :: Revoked => error ! ( "{} {:?}" , host, status) ,
537
+ Status :: NotCovered => info ! ( "{} {:?}" , host, status) ,
538
+ Status :: NotEnrolled => info ! ( "{} {:?}" , host, status) ,
539
+ Status :: Revoked => info ! ( "{} {:?}" , host, status) ,
524
540
}
525
541
match status {
526
542
Status :: Revoked => Ok ( CmdResult :: SomeRevoked ) ,
@@ -558,9 +574,9 @@ fn query_certs(db: &CRLiteDB, files: &[PathBuf]) -> Result<CmdResult, CRLiteDBEr
558
574
match query_cert_pem_or_der_bytes ( db, & input) {
559
575
Ok ( Status :: Revoked ) => {
560
576
found_revoked_certs = true ;
561
- error ! ( "{} {:?}" , file. display( ) , Status :: Revoked ) ;
577
+ info ! ( "{} {:?}" , file. display( ) , Status :: Revoked ) ;
562
578
}
563
- Ok ( status) => warn ! ( "{} {:?}" , file. display( ) , status) ,
579
+ Ok ( status) => info ! ( "{} {:?}" , file. display( ) , status) ,
564
580
Err ( e) => {
565
581
warn ! ( "Query error: {:?}" , e) ;
566
582
continue ;
@@ -581,11 +597,11 @@ fn query_crtsh_id(db: &CRLiteDB, id: &str) -> Result<CmdResult, CRLiteDBError> {
581
597
582
598
match query_cert_pem_or_der_bytes ( db, cert_bytes) {
583
599
Ok ( Status :: Revoked ) => {
584
- error ! ( "{} {:?}" , id, Status :: Revoked ) ;
600
+ info ! ( "{} {:?}" , id, Status :: Revoked ) ;
585
601
Ok ( CmdResult :: SomeRevoked )
586
602
}
587
603
Ok ( status) => {
588
- warn ! ( "{} {:?}" , id, status) ;
604
+ info ! ( "{} {:?}" , id, status) ;
589
605
Ok ( CmdResult :: NoneRevoked )
590
606
}
591
607
Err ( e) => {
@@ -604,20 +620,24 @@ fn query_crtsh_id(db: &CRLiteDB, id: &str) -> Result<CmdResult, CRLiteDBError> {
604
620
#[ derive( Parser ) ]
605
621
struct Cli {
606
622
/// Download a new CRLite filter and associated metadata from Firefox Remote Settings.
607
- #[ clap( long, arg_enum ) ]
623
+ #[ clap( long, value_enum ) ]
608
624
update : Option < RemoteSettingsInstance > ,
609
625
610
626
/// CRLite filter channel
611
627
#[ clap( long, value_enum, default_value = "default" ) ]
612
628
channel : CRLiteFilterChannel ,
613
629
614
630
/// CRLite directory e.g. <firefox profile>/security_state/.
615
- #[ clap( short, long, parse ( from_os_str ) , default_value = "./crlite_db/" ) ]
631
+ #[ clap( short, long, default_value = "./crlite_db/" ) ]
616
632
db : PathBuf ,
617
633
618
- /// Verbosity. -v => warning, -vv => info, -vvv => debug.
619
- #[ clap( short = 'v' , parse( from_occurrences) ) ]
620
- verbose : usize ,
634
+ /// Silence all output.
635
+ #[ clap( short = 'q' ) ]
636
+ quiet : bool ,
637
+
638
+ /// Include debug output in logs.
639
+ #[ clap( short = 'v' , action = clap:: ArgAction :: Count ) ]
640
+ verbose : u8 ,
621
641
622
642
#[ clap( subcommand) ]
623
643
command : Subcommand ,
@@ -626,14 +646,12 @@ struct Cli {
626
646
#[ derive( clap:: ValueEnum , Copy , Clone , Default , Deserialize , PartialEq ) ]
627
647
#[ serde( rename_all = "lowercase" ) ]
628
648
enum CRLiteFilterChannel {
629
- #[ serde( rename = "experimental+deltas" ) ]
630
- ExperimentalDeltas ,
631
649
#[ default]
632
650
Default ,
633
651
Compat ,
634
652
}
635
653
636
- #[ derive( Clone , clap:: ArgEnum ) ]
654
+ #[ derive( clap:: ValueEnum , Clone ) ]
637
655
enum RemoteSettingsInstance {
638
656
Prod ,
639
657
Stage ,
@@ -664,7 +682,8 @@ fn main() {
664
682
665
683
stderrlog:: new ( )
666
684
. module ( module_path ! ( ) )
667
- . verbosity ( args. verbose )
685
+ . quiet ( args. quiet )
686
+ . verbosity ( std:: cmp:: min ( 4 , ( args. verbose + 2 ) . into ( ) ) )
668
687
. init ( )
669
688
. unwrap ( ) ;
670
689
0 commit comments