55
66use std:: sync:: LazyLock ;
77
8- use crate :: { load_signing_key, load_witness_key , LookupKey , SequenceMetadata , CONFIG , ROOTS } ;
8+ use crate :: { load_signing_key, LookupKey , SequenceMetadata , CONFIG , ROOTS } ;
99use config:: TemporalInterval ;
1010use futures_util:: future:: try_join_all;
1111use generic_log_worker:: {
@@ -24,17 +24,17 @@ use tlog_tiles::{LogEntry, PendingLogEntry};
2424use worker:: * ;
2525
2626// The Maximum Merge Delay (MMD) of a log indicates the maximum period of time
27- // between when a SCT is issued and the corresponding entry is sequenced
28- // in the log. For static CT logs, this is effectively zero since SCT issuance
29- // happens only once the entry is sequenced. However, we can leave this value
30- // in the metadata as the default (1 day) .
31- const MAX_MERGE_DELAY : usize = 86_400 ;
27+ // between when a SCT is issued and the corresponding entry is sequenced in the
28+ // log. For Azul-based logs, this is effectively zero since SCT issuance happens
29+ // only once the entry is sequenced. However, we can leave this value in the
30+ // metadata as the maximum allowed in Chrome's policy, 60 seconds .
31+ const MAX_MERGE_DELAY_SECS : usize = 60 ;
3232
3333const UNKNOWN_LOG_MSG : & str = "unknown log" ;
3434
3535#[ serde_as]
3636#[ derive( Serialize ) ]
37- struct MetadataResponse < ' a > {
37+ struct LogV3JsonResponse < ' a > {
3838 #[ serde( skip_serializing_if = "Option::is_none" ) ]
3939 description : & ' a Option < String > ,
4040 #[ serde( skip_serializing_if = "Option::is_none" ) ]
@@ -43,8 +43,6 @@ struct MetadataResponse<'a> {
4343 log_id : & ' a [ u8 ] ,
4444 #[ serde_as( as = "Base64" ) ]
4545 key : & ' a [ u8 ] ,
46- #[ serde_as( as = "Base64" ) ]
47- witness_key : & ' a [ u8 ] ,
4846 mmd : usize ,
4947 submission_url : & ' a str ,
5048 monitoring_url : & ' a str ,
@@ -68,77 +66,101 @@ fn start() {
6866/// Panics if there are issues parsing route parameters, which should never happen.
6967#[ event( fetch, respond_with_errors) ]
7068async fn main ( req : Request , env : Env , _ctx : Context ) -> Result < Response > {
71- let router = Router :: new ( ) ;
72- router
73- . get ( "/logs/:log/ct/v1/get-roots" , |_req, ctx| {
74- let _name = valid_log_name ( & ctx) ?;
75- Response :: from_json ( & GetRootsResponse {
76- certificates : x509_util:: certs_to_bytes ( & ROOTS . certs ) . unwrap ( ) ,
77- } )
78- } )
79- . post_async ( "/logs/:log/ct/v1/add-chain" , |req, ctx| async move {
80- add_chain_or_pre_chain ( req, & ctx. env , valid_log_name ( & ctx) ?, false ) . await
81- } )
82- . post_async ( "/logs/:log/ct/v1/add-pre-chain" , |req, ctx| async move {
83- add_chain_or_pre_chain ( req, & ctx. env , valid_log_name ( & ctx) ?, true ) . await
84- } )
85- . get ( "/logs/:log/metadata" , |_req, ctx| {
86- let name = valid_log_name ( & ctx) ?;
87- let params = & CONFIG . logs [ name] ;
88- let verifying_key = load_signing_key ( & ctx. env , name) ?. verifying_key ( ) ;
89- let log_id =
90- & static_ct_api:: log_id_from_key ( verifying_key) . map_err ( |e| e. to_string ( ) ) ?;
91- let key = verifying_key
92- . to_public_key_der ( )
93- . map_err ( |e| e. to_string ( ) ) ?;
94- let witness_key = load_witness_key ( & ctx. env , name) ?;
95- let witness_key = witness_key
96- . verifying_key ( )
97- . to_public_key_der ( )
98- . map_err ( |e| e. to_string ( ) ) ?;
99- Response :: from_json ( & MetadataResponse {
100- description : & params. description ,
101- log_type : & params. log_type ,
102- log_id,
103- key : key. as_bytes ( ) ,
104- witness_key : witness_key. as_bytes ( ) ,
105- submission_url : & params. submission_url ,
106- monitoring_url : if params. monitoring_url . is_empty ( ) {
107- & params. submission_url
69+ // Use an outer router as middleware to check that the log name is valid.
70+ Router :: new ( )
71+ . or_else_any_method_async ( "/logs/:log/*route" , |req, ctx| async move {
72+ let name = if let Some ( name) = ctx. param ( "log" ) {
73+ if CONFIG . logs . contains_key ( name) {
74+ & name. clone ( )
10875 } else {
109- & params. monitoring_url
110- } ,
111- mmd : MAX_MERGE_DELAY ,
112- temporal_interval : & params. temporal_interval ,
113- } )
114- } )
115- . get_async ( "/logs/:log/metrics" , |_req, ctx| async move {
116- let name = valid_log_name ( & ctx) ?;
117- let stub = get_durable_object_stub (
118- & ctx. env ,
119- name,
120- None ,
121- "SEQUENCER" ,
122- CONFIG . logs [ name] . location_hint . as_deref ( ) ,
123- ) ?;
124- stub. fetch_with_str ( & format ! ( "http://fake_url.com{METRICS_ENDPOINT}" ) )
125- . await
126- } )
127- . get_async ( "/logs/:log/*key" , |_req, ctx| async move {
128- let name = valid_log_name ( & ctx) ?;
129- let key = ctx. param ( "key" ) . unwrap ( ) ;
130-
131- let bucket = load_public_bucket ( & ctx. env , name) ?;
132- if let Some ( obj) = bucket. get ( key) . execute ( ) . await ? {
133- Response :: from_body (
134- obj. body ( )
135- . ok_or ( "R2 object missing body" ) ?
136- . response_body ( ) ?,
137- )
138- . map ( |r| r. with_headers ( headers_from_http_metadata ( obj. http_metadata ( ) ) ) )
76+ return Err ( UNKNOWN_LOG_MSG . into ( ) ) ;
77+ }
13978 } else {
140- Response :: error ( "Not found" , 404 )
141- }
79+ return Err ( "missing 'log' route param" . into ( ) ) ;
80+ } ;
81+
82+ // Now that we've validated the log name, use an inner router to
83+ // handle the request.
84+ Router :: with_data ( name)
85+ . get ( "/logs/:log/ct/v1/get-roots" , |_req, _ctx| {
86+ Response :: from_json ( & GetRootsResponse {
87+ certificates : x509_util:: certs_to_bytes ( & ROOTS . certs ) . unwrap ( ) ,
88+ } )
89+ } )
90+ . post_async ( "/logs/:log/ct/v1/add-chain" , |req, ctx| async move {
91+ add_chain_or_pre_chain ( req, & ctx. env , ctx. data , false ) . await
92+ } )
93+ . post_async ( "/logs/:log/ct/v1/add-pre-chain" , |req, ctx| async move {
94+ add_chain_or_pre_chain ( req, & ctx. env , ctx. data , true ) . await
95+ } )
96+ . get ( "/logs/:log/log.v3.json" , |_req, ctx| {
97+ let name = ctx. data ;
98+ let params = & CONFIG . logs [ name] ;
99+ let verifying_key = load_signing_key ( & ctx. env , name) ?. verifying_key ( ) ;
100+ let log_id = & static_ct_api:: log_id_from_key ( verifying_key)
101+ . map_err ( |e| e. to_string ( ) ) ?;
102+ let key = verifying_key
103+ . to_public_key_der ( )
104+ . map_err ( |e| e. to_string ( ) ) ?;
105+ Response :: from_json ( & LogV3JsonResponse {
106+ description : & params. description ,
107+ log_type : & params. log_type ,
108+ log_id,
109+ key : key. as_bytes ( ) ,
110+ submission_url : & params. submission_url ,
111+ monitoring_url : if params. monitoring_url . is_empty ( ) {
112+ & params. submission_url
113+ } else {
114+ & params. monitoring_url
115+ } ,
116+ mmd : MAX_MERGE_DELAY_SECS ,
117+ temporal_interval : & params. temporal_interval ,
118+ } )
119+ } )
120+ . get_async ( "/logs/:log/metrics" , |_req, ctx| async move {
121+ let name = ctx. data ;
122+ let stub = get_durable_object_stub (
123+ & ctx. env ,
124+ name,
125+ None ,
126+ "SEQUENCER" ,
127+ CONFIG . logs [ name] . location_hint . as_deref ( ) ,
128+ ) ?;
129+ stub. fetch_with_str ( & format ! ( "http://fake_url.com{METRICS_ENDPOINT}" ) )
130+ . await
131+ } )
132+ . get_async ( "/logs/:log/*key" , |_req, ctx| async move {
133+ let name = ctx. data ;
134+ let key = ctx. param ( "key" ) . unwrap ( ) ;
135+
136+ // Enable direct access to the bucket via the Worker if
137+ // monitoring_url is unspecified.
138+ if CONFIG . logs [ name] . monitoring_url . is_empty ( ) {
139+ let bucket = load_public_bucket ( & ctx. env , name) ?;
140+ if let Some ( obj) = bucket. get ( key) . execute ( ) . await ? {
141+ Response :: from_body (
142+ obj. body ( )
143+ . ok_or ( "R2 object missing body" ) ?
144+ . response_body ( ) ?,
145+ )
146+ . map ( |r| {
147+ r. with_headers ( headers_from_http_metadata ( obj. http_metadata ( ) ) )
148+ } )
149+ } else {
150+ Response :: error ( "Not found" , 404 )
151+ }
152+ } else {
153+ Response :: error (
154+ format ! (
155+ "Use {} for monitoring API" ,
156+ CONFIG . logs[ name] . monitoring_url
157+ ) ,
158+ 403 ,
159+ )
160+ }
161+ } )
162+ . run ( req, ctx. env )
163+ . await
142164 } )
143165 . run ( req, env)
144166 . await
@@ -269,18 +291,6 @@ async fn add_chain_or_pre_chain(
269291 Response :: from_json ( & sct)
270292}
271293
272- fn valid_log_name ( ctx : & RouteContext < ( ) > ) -> Result < & str > {
273- if let Some ( name) = ctx. param ( "log" ) {
274- if CONFIG . logs . contains_key ( name) {
275- Ok ( name)
276- } else {
277- Err ( UNKNOWN_LOG_MSG . into ( ) )
278- }
279- } else {
280- Err ( "missing 'log' route param" . into ( ) )
281- }
282- }
283-
284294fn batcher_id_from_lookup_key ( key : & LookupKey , num_batchers : u8 ) -> u8 {
285295 key[ 0 ] % num_batchers
286296}
0 commit comments