@@ -155,20 +155,21 @@ async fn dispatch(req: Request, state: &Arc<Mutex<AgentState>>) -> Response {
155155 }
156156 Err ( e) => Err ( e) ,
157157 } ;
158+ let secs = clear_after_secs. unwrap_or ( s. clipboard_clear_secs ) ;
158159 s. touch ( ) ;
159160 drop ( s) ;
160161 match outcome {
161162 Ok ( value) => {
162- schedule_clipboard_clear ( state. clone ( ) , value, clear_after_secs) ;
163- Response :: Ok
163+ schedule_clipboard_clear ( state. clone ( ) , value, secs) ;
164+ Response :: Copied ( vault_ipc:: proto:: Copied {
165+ clear_after_secs : secs,
166+ } )
164167 }
165168 Err ( e) => Response :: Error ( e) ,
166169 }
167170 }
168171 #[ cfg( not( feature = "clipboard" ) ) ]
169- Request :: Copy { .. } => Response :: Error ( vault_ipc:: proto:: Error :: Internal (
170- "clipboard support not compiled in" . to_owned ( ) ,
171- ) ) ,
172+ Request :: Copy { .. } => Response :: Error ( vault_ipc:: proto:: Error :: ClipboardUnavailable ) ,
172173 #[ cfg( feature = "clipboard" ) ]
173174 Request :: CopyText {
174175 text,
@@ -192,20 +193,21 @@ async fn dispatch(req: Request, state: &Arc<Mutex<AgentState>>) -> Response {
192193 } else {
193194 Err ( vault_ipc:: proto:: Error :: Locked )
194195 } ;
196+ let secs = clear_after_secs. unwrap_or ( s. clipboard_clear_secs ) ;
195197 s. touch ( ) ;
196198 drop ( s) ;
197199 match outcome {
198200 Ok ( value) => {
199- schedule_clipboard_clear ( state. clone ( ) , value, clear_after_secs) ;
200- Response :: Ok
201+ schedule_clipboard_clear ( state. clone ( ) , value, secs) ;
202+ Response :: Copied ( vault_ipc:: proto:: Copied {
203+ clear_after_secs : secs,
204+ } )
201205 }
202206 Err ( e) => Response :: Error ( e) ,
203207 }
204208 }
205209 #[ cfg( not( feature = "clipboard" ) ) ]
206- Request :: CopyText { .. } => Response :: Error ( vault_ipc:: proto:: Error :: Internal (
207- "clipboard support not compiled in" . to_owned ( ) ,
208- ) ) ,
210+ Request :: CopyText { .. } => Response :: Error ( vault_ipc:: proto:: Error :: ClipboardUnavailable ) ,
209211 Request :: Remove { selector } => {
210212 // Hold the agent mutex across the network call. Vault is
211213 // single-user / single-agent, so request concurrency is low and
@@ -284,26 +286,18 @@ async fn dispatch(req: Request, state: &Arc<Mutex<AgentState>>) -> Response {
284286 }
285287}
286288
287- /// Default seconds before the agent wipes a copied secret from the clipboard.
288- ///
289- /// 30 s follows common password-manager practice (and Vault PRD §7.2): long
290- /// enough to paste, short enough to bound exposure. `Request::Copy` overrides
291- /// per call; config-driven tuning lands in a later slice.
292- #[ cfg( feature = "clipboard" ) ]
293- const DEFAULT_CLIPBOARD_CLEAR_SECS : u64 = 30 ;
294-
295- /// Spawn a one-shot task that wipes the clipboard after `clear_after_secs` (or
296- /// the default), but only if it still holds the value we copied. `Some(0)`
297- /// disables the auto-clear. The task carries the secret so the clear survives
298- /// the requesting client quitting.
289+ /// Spawn a one-shot task that wipes the clipboard after `secs` (the effective
290+ /// interval — the caller already applied the agent default), but only if it
291+ /// still holds the value we copied. `0` disables the auto-clear. The task
292+ /// carries the secret so the clear survives the requesting client quitting;
293+ /// if the *agent* goes down first, `AgentState::lock`'s sweep covers it.
299294#[ cfg( feature = "clipboard" ) ]
300295fn schedule_clipboard_clear (
301296 state : Arc < Mutex < AgentState > > ,
302297 value : zeroize:: Zeroizing < String > ,
303- clear_after_secs : Option < u64 > ,
298+ secs : u64 ,
304299) {
305300 use tokio:: time:: { Duration , sleep} ;
306- let secs = clear_after_secs. unwrap_or ( DEFAULT_CLIPBOARD_CLEAR_SECS ) ;
307301 if secs == 0 {
308302 return ;
309303 }
0 commit comments