11use crate :: currency:: Address ;
22use anyhow:: { bail, Result } ;
33use base64:: prelude:: * ;
4+ use cached:: proc_macro:: once;
45use chrono:: { DateTime , Utc } ;
56use git2:: { Commit , Oid , Repository , Sort } ;
6- use std:: process:: Command ;
7+ use std:: { path :: PathBuf , process:: Command } ;
78use tempfile:: TempDir ;
89use tracing:: { debug, info, instrument} ;
910
@@ -29,13 +30,6 @@ impl Contributor {
2930 }
3031}
3132
32- #[ derive( Debug , Clone ) ]
33- pub struct Transaction {
34- pub amount : String ,
35- pub timestamp : u64 ,
36- pub contributor_name : String ,
37- }
38-
3933///
4034pub struct TurbineRepo {
4135 /// Branch to track
@@ -91,6 +85,41 @@ fn get_public_key_id(commit: &Commit) -> Result<String> {
9185 bail ! ( "Failed to get GPG public key ID" ) ;
9286}
9387
88+ /// Receive the public key for the given commit.
89+ #[ once( time = "36000" , result = true ) ]
90+ fn import_public_key ( commit : & Commit ) -> Result < ( ) > {
91+ Command :: new ( "gpg" )
92+ . arg ( "--keyserver" )
93+ . arg ( std:: env:: var ( "TURBINE_GPG_KEYSERVER" ) . unwrap_or ( "hkp://keyserver.ubuntu.com" . into ( ) ) )
94+ . arg ( "--recv-keys" )
95+ . arg ( get_public_key_id ( & commit) ?)
96+ . spawn ( ) ?
97+ . wait ( ) ?;
98+
99+ Ok ( ( ) )
100+ }
101+
102+ /// Verify a commit's GPG signature and return its key ID.
103+ #[ once( result = true ) ]
104+ fn verify_signature ( repo : PathBuf , commit : & Commit ) -> Result < String > {
105+ // Receive the public key first
106+ import_public_key ( commit) ?;
107+
108+ // TODO verify the signature ourselves (gpgme?)
109+ if Command :: new ( "git" )
110+ . arg ( "verify-commit" )
111+ . arg ( commit. id ( ) . to_string ( ) )
112+ . current_dir ( repo)
113+ . spawn ( ) ?
114+ . wait ( ) ?
115+ . success ( )
116+ {
117+ Ok ( get_public_key_id ( & commit) ?)
118+ } else {
119+ bail ! ( "Failed to verify signature" ) ;
120+ }
121+ }
122+
94123impl TurbineRepo {
95124 pub fn new ( remote : & str , branch : & str ) -> Result < Self > {
96125 let tmp = tempfile:: tempdir ( ) ?;
@@ -132,34 +161,33 @@ impl TurbineRepo {
132161 }
133162 }
134163
135- /// Verify a commit's GPG signature and return its key ID.
136- #[ instrument( skip( self ) , ret, level = "trace" ) ]
137- fn verify_signature ( & self , commit : & Commit ) -> Result < String > {
138- // Receive the public key first
139- Command :: new ( "gpg" )
140- . arg ( "--keyserver" )
141- . arg (
142- std:: env:: var ( "TURBINE_GPG_KEYSERVER" )
143- . unwrap_or ( "hkp://keyserver.ubuntu.com" . into ( ) ) ,
144- )
145- . arg ( "--recv-keys" )
146- . arg ( get_public_key_id ( & commit) ?)
147- . spawn ( ) ?
148- . wait ( ) ?;
149-
150- // TODO verify the signature ourselves (gpgme?)
151- if Command :: new ( "git" )
152- . arg ( "verify-commit" )
153- . arg ( commit. id ( ) . to_string ( ) )
154- . current_dir ( self . tmp . path ( ) )
155- . spawn ( ) ?
156- . wait ( ) ?
157- . success ( )
158- {
159- Ok ( get_public_key_id ( & commit) ?)
160- } else {
161- bail ! ( "Failed to verify signature" ) ;
164+ /// Get all signed commits (whether their signatures are valid or not).
165+ pub fn get_signed_commits ( & self ) -> Result < Vec < Oid > > {
166+ let mut revwalk = self . container . revwalk ( ) ?;
167+ let branch = self
168+ . container
169+ . find_branch ( & self . branch , git2:: BranchType :: Local ) ?;
170+ let branch_ref = branch. into_reference ( ) ;
171+
172+ revwalk. push ( branch_ref. target ( ) . unwrap ( ) ) ?;
173+
174+ let mut commits = Vec :: new ( ) ;
175+ loop {
176+ if let Some ( next) = revwalk. next ( ) {
177+ let commit = self . container . find_commit ( next?) ?;
178+
179+ // Check for GPG signature
180+ if let Some ( header) = commit. raw_header ( ) {
181+ if header. contains ( "gpgsig" ) {
182+ commits. push ( commit. id ( ) ) ;
183+ }
184+ }
185+ } else {
186+ break ;
187+ }
162188 }
189+
190+ Ok ( commits)
163191 }
164192
165193 pub fn refresh ( & mut self ) -> Result < ( ) > {
@@ -197,7 +225,7 @@ impl TurbineRepo {
197225 }
198226 }
199227
200- if let Ok ( key_id) = self . verify_signature ( & commit) {
228+ if let Ok ( key_id) = verify_signature ( self . tmp . path ( ) . to_path_buf ( ) , & commit) {
201229 if let Some ( message) = commit. message ( ) {
202230 #[ cfg( feature = "monero" ) ]
203231 if let Some ( ( _, address) ) = message. split_once ( "XMR" ) {
@@ -250,7 +278,7 @@ impl TurbineRepo {
250278 }
251279 }
252280
253- if let Ok ( key_id) = self . verify_signature ( & commit) {
281+ if let Ok ( key_id) = verify_signature ( self . tmp . path ( ) . to_path_buf ( ) , & commit) {
254282 if let Some ( contributor) = self
255283 . contributors
256284 . iter_mut ( )
0 commit comments