@@ -5,9 +5,11 @@ use crate::privatebin::{Comment, DecryptedComment, Paste, PostCommentResponse, P
55use crate :: util:: check_filesize;
66use crate :: DecryptedPaste ;
77use rand_chacha:: rand_core:: { RngCore , SeedableRng } ;
8+ use reqwest:: tls:: Certificate ;
89use reqwest:: { Method , Url } ;
910use scraper:: { Html , Selector } ;
1011use std:: str:: FromStr ;
12+ use std:: time:: Duration ;
1113
1214#[ cfg_attr( feature = "uniffi" , derive( uniffi:: Object ) ) ]
1315pub struct API {
@@ -29,6 +31,34 @@ impl API {
2931}
3032
3133impl API {
34+ fn build_client ( & self ) -> PbResult < reqwest:: blocking:: Client > {
35+ let mut builder = reqwest:: blocking:: Client :: builder ( ) ;
36+
37+ let timeout_secs = self . opts . timeout . unwrap_or ( 30 ) ;
38+ builder = builder
39+ . connect_timeout ( Duration :: from_secs ( timeout_secs) )
40+ . timeout ( Duration :: from_secs ( timeout_secs * 4 ) ) ;
41+
42+ if self . opts . insecure {
43+ builder = builder. danger_accept_invalid_certs ( true ) ;
44+ }
45+
46+ if let Some ( ref ca_path) = self . opts . ca_cert {
47+ let pem = std:: fs:: read ( ca_path) . map_err ( |e| {
48+ PbError :: InvalidCertificate ( format ! (
49+ "failed to read CA cert {}: {}" ,
50+ ca_path. display( ) ,
51+ e
52+ ) )
53+ } ) ?;
54+ for cert in pem_certs_from_bundle ( & pem) ? {
55+ builder = builder. add_root_certificate ( cert) ;
56+ }
57+ }
58+
59+ Ok ( builder. build ( ) ?)
60+ }
61+
3262 fn get_oidc_access_token ( & self ) -> PbResult < String > {
3363 let oidc_token_endpoint = self . opts . oidc_token_url . as_ref ( ) . unwrap ( ) ;
3464 let oidc_client_id = self . opts . oidc_client_id . as_ref ( ) . unwrap ( ) ;
@@ -41,7 +71,7 @@ impl API {
4171 post_fields. insert ( "username" , oidc_username) ;
4272 post_fields. insert ( "password" , oidc_password) ;
4373
44- let client = reqwest :: blocking :: Client :: builder ( ) . build ( ) ?;
74+ let client = self . build_client ( ) ?;
4575 let mut request = client. post ( oidc_token_endpoint) ;
4676 request = request. form ( & post_fields) ;
4777
@@ -78,7 +108,7 @@ impl API {
78108 url : Url ,
79109 json_request : bool ,
80110 ) -> PbResult < reqwest:: blocking:: RequestBuilder > {
81- let client = reqwest :: blocking :: Client :: builder ( ) . build ( ) ?;
111+ let client = self . build_client ( ) ?;
82112
83113 let mut request = client. request ( Method :: from_str ( method) . unwrap ( ) , url) ;
84114 if json_request {
@@ -95,6 +125,35 @@ impl API {
95125 }
96126}
97127
128+ fn pem_certs_from_bundle ( pem : & [ u8 ] ) -> PbResult < Vec < Certificate > > {
129+ let pem_str = std:: str:: from_utf8 ( pem)
130+ . map_err ( |e| PbError :: InvalidCertificate ( format ! ( "CA cert is not valid UTF-8: {}" , e) ) ) ?;
131+ let mut certs = Vec :: new ( ) ;
132+ let mut current = String :: new ( ) ;
133+ let mut in_cert = false ;
134+ for line in pem_str. lines ( ) {
135+ if line. contains ( "BEGIN CERTIFICATE" ) {
136+ in_cert = true ;
137+ current. clear ( ) ;
138+ current. push_str ( line) ;
139+ current. push ( '\n' ) ;
140+ } else if line. contains ( "END CERTIFICATE" ) {
141+ current. push_str ( line) ;
142+ current. push ( '\n' ) ;
143+ certs. push (
144+ Certificate :: from_pem ( current. as_bytes ( ) ) . map_err ( |e| {
145+ PbError :: InvalidCertificate ( format ! ( "invalid certificate in bundle: {}" , e) )
146+ } ) ?,
147+ ) ;
148+ in_cert = false ;
149+ } else if in_cert {
150+ current. push_str ( line) ;
151+ current. push ( '\n' ) ;
152+ }
153+ }
154+ Ok ( certs)
155+ }
156+
98157#[ cfg_attr( feature = "uniffi" , uniffi:: export) ]
99158impl API {
100159 pub fn get_paste ( & self , paste_id : & str ) -> PbResult < Paste > {
0 commit comments