We will handle the Firebase admin SDK private key in a USB drive then login with it, once the USB is connected using the admin SDK for Java documentations.

The private key of your Firebase admin SDK is a sensitive file and shouldn’t be included in your project files or saved on a fixed location on your machine, so we will see how we can save it and access it till login and retrieving data from the cloud firestore using a javaFX project.

Preparing the USB

We create a firebase new project, then need to download a private key for the admin SDK from Project Settings > Service accounts , then we choose Java and click Generate new private key.

I will rename the key to admin.json and put it in a clean USB.

From Database, we create a new Cloud database and choose the locked mode. We insert some demo data as below:

We also need to go to authentication and enable email login, then add a user because we will need its uid in the coming steps.

Creating a new project in Intellij

We create a new project in Intellij, we choose JavaFX application, and it is preferred to use JDK 8 not 11 where the JavaFX is not included by default.

We create a fxml file login_layout.fxml:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.AnchorPane?>

<AnchorPane prefHeight="400.0" prefWidth="600.0" style="-fx-border-width: 3; -fx-border-color: coral" xmlns="http://javafx.com/javafx/8.0.181" xmlns:fx="http://javafx.com/fxml/1" fx:controller="sample.LoginController">
   <children>
      <Label layoutX="145.0" layoutY="182.0" style="-fx-font-size: 25" text="Please plug the USB to Login" fx:id="lb_login"/>
   </children>
</AnchorPane>

We create a class AutoDetect.java that will watch the drives and detect when one is added or removed:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
import javafx.application.Platform;
import javafx.scene.control.Label;
import java.io.File;

public class AutoDetect {

    File[] oldListRoot = File.listRoots();
    public static String usb = null;

    public void waitForNotifying(Label message) {
        Thread t = new Thread(new Runnable() {
            public void run() {
                while (true) {
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    if (File.listRoots().length > oldListRoot.length) {
                        System.out.println("new drive detected");
                        oldListRoot = File.listRoots();
                        System.out.println("drive "+oldListRoot[oldListRoot.length-1]+" detected");
                        Platform.runLater(new Runnable() {
                            @Override                            public void run() {
                                message.setText("USB is connected");
                            }
                        });
                        if (checkUSB(oldListRoot[oldListRoot.length-1], message)){
                            usb = oldListRoot[oldListRoot.length-1].getAbsolutePath();
                        }
                    } else if (File.listRoots().length < oldListRoot.length) {
                        System.out.println(oldListRoot[oldListRoot.length-1]+" drive removed");
                        oldListRoot = File.listRoots();
                        Platform.runLater(new Runnable() {
                            @Override
                            public void run() {
                                message.setText("USB has been removed");
                            }
                        });
                    }

                }
            }
        });
        t.start();
    }

    private boolean checkUSB(File file, Label message) {
        File admin = new File(file.getAbsolutePath() + File.separator +  "admin.json");
        if(admin.exists()){
            Platform.runLater(new Runnable() {
                @Override
                public void run() {
                    message.setText("Admin private key has been found");
                }
            });
            return true;
        }else{
            Platform.runLater(new Runnable() {
                @Override
                public void run() {
                    message.setText("Admin private key has not been found");
                }
            });
            return false;
        }
    }

    public String getUsb() {
        return usb;
    }
}

We create a model User.java to get the data objects from the firebase firestore database:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public class User {
    String name, email;
    
    public User(){
        
    }

    public User(String name, String email) {
        this.name = name;
        this.email = email;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }
}

Now, we need to add the Firebase modules/dependencies, we can use maven but I prefer to download them all and add them as local library from here and then I past them to lib folder in my project > choose all of them > right click on them > add as library..

Now we go to our Main.java to initialize everything together and to preform the best listening to the USB plugging:

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
import com.google.api.core.ApiFuture;
import com.google.auth.oauth2.GoogleCredentials;
import com.google.cloud.firestore.DocumentSnapshot;
import com.google.cloud.firestore.Firestore;
import com.google.cloud.firestore.QueryDocumentSnapshot;
import com.google.cloud.firestore.QuerySnapshot;
import com.google.firebase.FirebaseApp;
import com.google.firebase.FirebaseOptions;
import com.google.firebase.auth.FirebaseAuth;
import com.google.firebase.auth.FirebaseAuthException;
import com.google.firebase.cloud.FirestoreClient;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.stage.Stage;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;

public class Main extends Application {

    private Label message;
    @Override
    public void start(Stage primaryStage) throws Exception{
        Parent root = FXMLLoader.load(getClass().getResource("login_layout.fxml"));
        Scene scene = new Scene(root);
        primaryStage.setScene(scene);
        primaryStage.show();

        message = (Label) scene.lookup("#lb_login");
        AutoDetect autoDetect  = new AutoDetect();
        autoDetect.waitForNotifying(message);

        //Listening
        startListening(autoDetect, primaryStage);
    }

    private void startListening(AutoDetect autoDetect, Stage primaryStage) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                while (true){
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    String usb = autoDetect.getUsb();
                    if (usb != null){
                        if (login(usb, autoDetect, primaryStage)){

                            break;
                        }
                    }else{
                        Platform.runLater(() -> message.setText("Please plug the USB to Login"));
                    }
                }
            }
        }).start();
    }

    private boolean login(String usb, AutoDetect autoDetect, Stage primaryStage) {
        File admin = new File(usb + File.separator + "admin.json");
        ArrayList<User> users = new ArrayList<>();
        try {
            Platform.runLater(() -> message.setText("Logging ..."));
            FileInputStream serviceAccount  = new FileInputStream(admin);
            FirebaseOptions options = new FirebaseOptions.Builder()
                    .setCredentials(GoogleCredentials.fromStream(serviceAccount))
                    // Your Database URL can be found in your firebase console -> your project
                    .setDatabaseUrl("https://tutorial-8b2f6.firebaseio.com/")
                    .build();
            FirebaseApp finestayApp = null;
            boolean hasBeenInitialized=false;
            List<FirebaseApp> firebaseApps = FirebaseApp.getApps();
            for(FirebaseApp app : firebaseApps){
                if(app.getName().equals(FirebaseApp.DEFAULT_APP_NAME)){
                    hasBeenInitialized=true;
                    finestayApp = app;
                }
            }

            if(!hasBeenInitialized) {
                finestayApp = FirebaseApp.initializeApp(options);
            }
            String token = FirebaseAuth.getInstance().createCustomToken("8Ne5d8F1zFf1d2jS4qUHA4hd0nw1"); // This is the user UID that we created

            Firestore db = FirestoreClient.getFirestore(finestayApp);
            ApiFuture<QuerySnapshot> future =
                    db.collection("users").get();
            List<QueryDocumentSnapshot> documents = future.get().getDocuments();
            int i = 1;
            for (DocumentSnapshot document : documents) {
                int finalI = i;
                Platform.runLater(() -> message.setText("Fetching  data from DB: " + finalI + "/" + documents.size()));
                User user  = document.toObject(User.class);
                users.add(user);
                i ++;
            }
            FirebaseApp finalFinestayApp = finestayApp;
            Platform.runLater(() -> {
                message.setText("Done.");
                printUsersFromDB(users, usb, finalFinestayApp);

            });
            return true;
        } catch (IOException | FirebaseAuthException | InterruptedException | ExecutionException e) {
            e.printStackTrace();
            Platform.runLater(() -> message.setText("There was an error!"));
            return false;
        }
    }

    private void printUsersFromDB(ArrayList<User> users, String usb, FirebaseApp finalFinestayApp) {
        for (User user : users){
            System.out.println("Name: " + user.getName() + "\tEmail: " + user.getEmail());
        }
    }


    public static void main(String[] args) {
        launch(args);
    }
}

Result