@@ -24,6 +24,13 @@ use sync15::engine::{CollSyncIds, CollectionRequest, EngineSyncAssociation, Sync
2424use sync15:: { telemetry, ServerTimestamp } ;
2525use sync_guid:: Guid ;
2626
27+ // The Desktop FxA session-credentials pseudo-login. Firefox stores its account
28+ // credentials as a login under this origin; it must never be synced. This
29+ // mirrors the exclusion the JS `PasswordEngine` does via
30+ // `Utils.getSyncCredentialsHosts()`. Only relevant on Desktop (mobile never has
31+ // such a login), but it's harmless to filter everywhere.
32+ const FXA_CREDENTIALS_ORIGIN : & str = "chrome://FirefoxAccounts" ;
33+
2734// The sync engine.
2835pub struct LoginsSyncEngine {
2936 pub store : Arc < LoginStore > ,
@@ -246,26 +253,31 @@ impl LoginsSyncEngine {
246253 let mut stmt = db. prepare_cached ( & format ! (
247254 "SELECT L.*, M.enc_unknown_fields
248255 FROM loginsL L LEFT JOIN loginsM M ON L.guid = M.guid
249- WHERE sync_status IS NOT {synced}" ,
256+ WHERE sync_status IS NOT {synced}
257+ -- Never sync Desktop's FxA session-credentials pseudo-login.
258+ AND L.origin IS NOT :fxa_origin" ,
250259 synced = SyncStatus :: Synced as u8
251260 ) ) ?;
252- let bsos = stmt. query_and_then ( [ ] , |row| {
253- self . scope . err_if_interrupted ( ) ?;
254- Ok ( if row. get :: < _ , bool > ( "is_deleted" ) ? {
255- let envelope = OutgoingEnvelope {
256- id : row. get :: < _ , String > ( "guid" ) ?. into ( ) ,
257- sortindex : Some ( TOMBSTONE_SORTINDEX ) ,
258- ..Default :: default ( )
259- } ;
260- OutgoingBso :: new_tombstone ( envelope)
261- } else {
262- let unknown = row. get :: < _ , Option < String > > ( "enc_unknown_fields" ) ?;
263- let mut bso =
264- EncryptedLogin :: from_row ( row) ?. into_bso ( self . encdec . as_ref ( ) , unknown) ?;
265- bso. envelope . sortindex = Some ( DEFAULT_SORTINDEX ) ;
266- bso
267- } )
268- } ) ?;
261+ let bsos = stmt. query_and_then (
262+ named_params ! { ":fxa_origin" : FXA_CREDENTIALS_ORIGIN } ,
263+ |row| {
264+ self . scope . err_if_interrupted ( ) ?;
265+ Ok ( if row. get :: < _ , bool > ( "is_deleted" ) ? {
266+ let envelope = OutgoingEnvelope {
267+ id : row. get :: < _ , String > ( "guid" ) ?. into ( ) ,
268+ sortindex : Some ( TOMBSTONE_SORTINDEX ) ,
269+ ..Default :: default ( )
270+ } ;
271+ OutgoingBso :: new_tombstone ( envelope)
272+ } else {
273+ let unknown = row. get :: < _ , Option < String > > ( "enc_unknown_fields" ) ?;
274+ let mut bso =
275+ EncryptedLogin :: from_row ( row) ?. into_bso ( self . encdec . as_ref ( ) , unknown) ?;
276+ bso. envelope . sortindex = Some ( DEFAULT_SORTINDEX ) ;
277+ bso
278+ } )
279+ } ,
280+ ) ?;
269281 bsos. collect :: < Result < _ > > ( )
270282 }
271283
@@ -808,6 +820,44 @@ mod tests {
808820 assert ! ( changes[ "changed" ] . get( "deleted" ) . is_none( ) ) ;
809821 }
810822
823+ #[ test]
824+ fn test_fetch_outgoing_excludes_fxa_credentials ( ) {
825+ ensure_initialized ( ) ;
826+ let store = LoginStore :: new_in_memory ( ) ;
827+
828+ // A normal local login that should be uploaded.
829+ insert_login ( & store. lock_db ( ) . unwrap ( ) , "normal" , Some ( "password" ) , None ) ;
830+
831+ // Desktop's FxA session-credentials pseudo-login must never be synced.
832+ store
833+ . add ( LoginEntry {
834+ origin : FXA_CREDENTIALS_ORIGIN . to_string ( ) ,
835+ http_realm : Some ( "Firefox Accounts credentials" . to_string ( ) ) ,
836+ username : "uid" . to_string ( ) ,
837+ password : "sync-token" . to_string ( ) ,
838+ ..Default :: default ( )
839+ } )
840+ . unwrap ( ) ;
841+
842+ let changeset = run_fetch_outgoing ( store) ;
843+ let changes: HashMap < String , serde_json:: Value > = changeset
844+ . into_iter ( )
845+ . map ( |b| {
846+ (
847+ b. envelope . id . to_string ( ) ,
848+ serde_json:: from_str ( & b. payload ) . unwrap ( ) ,
849+ )
850+ } )
851+ . collect ( ) ;
852+
853+ // The normal login still uploads; nothing pointing at the FxA origin
854+ // is outgoing.
855+ assert ! ( changes. contains_key( "normal" ) ) ;
856+ assert ! ( changes
857+ . values( )
858+ . all( |payload| payload[ "hostname" ] != FXA_CREDENTIALS_ORIGIN ) ) ;
859+ }
860+
811861 #[ test]
812862 fn test_bad_record ( ) {
813863 ensure_initialized ( ) ;
0 commit comments