1nikolas / play-integrity-checker-app

Get info about your Device Integrity through the Play Intergrity API
MIT License
333 stars 47 forks source link

Why PlayIntegrity api call resulting in Error code :GOOGLE_SERVER_UNAVAILABLE Where am i going wrong ? #10

Closed varunsinghNW18 closed 2 years ago

varunsinghNW18 commented 2 years ago

Following your example but unfortunately am not getting the token since it is giving an error as GOOGLE_SERVER__UNAVAILABLE. Have done the ground works like Play & Cloud console enablement.

You can check my code:

       @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // playIntegritySetup.lol();
        getToken();
    }

    private void getToken() {
        String nonce = Base64.encodeToString(generateNonce(50).getBytes(),   Base64.URL_SAFE | Base64.NO_WRAP | Base64.NO_PADDING);

        // Create an instance of a manager.
        IntegrityManager integrityManager = IntegrityManagerFactory.create(getApplicationContext());

        // Request the integrity token by providing a nonce.
        Task<IntegrityTokenResponse> integrityTokenResponse = integrityManager.requestIntegrityToken(
                IntegrityTokenRequest.builder()
                        .setNonce(nonce)
                        .build());

        integrityTokenResponse.addOnSuccessListener(new OnSuccessListener<IntegrityTokenResponse>() {
            @Override
            public void onSuccess(IntegrityTokenResponse integrityTokenResponse) {
                String integrityToken = integrityTokenResponse.token();
                SplashActivity.this.doIntegrityCheck(integrityToken);
                Log.e("Integrity Token", "integrity token from the app" + integrityToken);

            }
        });

        integrityTokenResponse.addOnFailureListener(e -> showErrorDialog("Error getting token from Google. Google said: " + getErrorText(e)));
    }

    private void doIntegrityCheck(String token) {
        AtomicBoolean hasError = new AtomicBoolean(false);

        Observable.fromCallable(() -> {

                    OkHttpClient okHttpClient = new OkHttpClient();
                    Response response = okHttpClient.newCall(new Request.Builder().url("money control url" + "token from backend server" + token).build()).execute();
                    Log.e("Token", "token from the app" + token);

                    if (!response.isSuccessful()) {
                        hasError.set(true);
                        return "Api request error. Code: " + response.code();

                    }
                    ResponseBody responseBody = response.body();
                    if (responseBody == null) {
                        hasError.set(true);

                        return "Api request error. Empty response";

                    }
                    JSONObject responseJson = new JSONObject(responseBody.string());
                    if (responseJson.has("error")) {
                        hasError.set(true);

                        return "Api request error: " + responseJson.getString("error");

                    }
                    if (!responseJson.has("deviceIntegrity")) {
                        hasError.set(true);

                    }

                    return responseJson.getJSONObject("deviceIntegrity").toString();
                }) // Execute in IO thread, i.e. background thread.
                .subscribeOn(Schedulers.io())
                // report or post the result to main thread.
                .observeOn(AndroidSchedulers.mainThread())
                // execute this RxJava
                .subscribe(new Observer<String>() {
                    @Override
                    public void onSubscribe(Disposable d) {

                    }

                    @Override
                    public void onNext(String result) {
                        if (hasError.get()) {
                            if (result.contains("MEETS_DEVICE_INTEGRITY") && result.contains("MEETS_BASIC_INTEGRITY")) {
                               //Here goes my other code

                            }
                        }
                    }

                    @Override
                    public void onError(Throwable e) {

                    }

                    @Override
                    public void onComplete() {

                    }
                });
    }

  private String getErrorText(Exception e) {
        String msg = e.getMessage();
        if (msg == null) {
            return "Unknown Error";
        }

        //the error code
        int errorCode = Integer.parseInt(msg.replaceAll("\n", "").replaceAll(":(.*)", ""));
        switch (errorCode) {
            case IntegrityErrorCode.API_NOT_AVAILABLE:
                return "API_NOT_AVAILABLE";
            case IntegrityErrorCode.NO_ERROR:
                return "NO_ERROR";
            case IntegrityErrorCode.INTERNAL_ERROR:
                return "INTERNAL_ERROR";
            case IntegrityErrorCode.NETWORK_ERROR:
                return "NETWORK_ERROR";
            case IntegrityErrorCode.PLAY_STORE_NOT_FOUND:
                return "PLAY_STORE_NOT_FOUND";
            case IntegrityErrorCode.PLAY_STORE_ACCOUNT_NOT_FOUND:
                return "PLAY_STORE_ACCOUNT_NOT_FOUND";
            case IntegrityErrorCode.APP_NOT_INSTALLED:
                return "APP_NOT_INSTALLED";
            case IntegrityErrorCode.PLAY_SERVICES_NOT_FOUND:
                return "PLAY_SERVICES_NOT_FOUND";
            case IntegrityErrorCode.APP_UID_MISMATCH:
                return "APP_UID_MISMATCH";
            case IntegrityErrorCode.TOO_MANY_REQUESTS:
                return "TOO_MANY_REQUESTS";
            case IntegrityErrorCode.CANNOT_BIND_TO_SERVICE:
                return "CANNOT_BIND_TO_SERVICE";
            case IntegrityErrorCode.NONCE_TOO_SHORT:
                return "NONCE_TOO_SHORT";
            case IntegrityErrorCode.NONCE_TOO_LONG:
                return "NONCE_TOO_LONG";
            case IntegrityErrorCode.GOOGLE_SERVER_UNAVAILABLE:
                return "GOOGLE_SERVER_UNAVAILABLE";
            case IntegrityErrorCode.NONCE_IS_NOT_BASE64:
                return "NONCE_IS_NOT_BASE64";
            default:
                return "Unknown Error";
        }
    }

    private String generateNonce(int length) {
        String nonce = "";
        String allowed = getNonce();
        for (int i = 0; i < length; i++) {
            nonce = nonce.concat(String.valueOf(allowed.charAt((int) Math.floor(Math.random() * allowed.length()))));
        }
        return nonce;
    }

    public native String getNonce();

    static {
        System.loadLibrary("all-keys");
    }
1nikolas commented 2 years ago

Have you tried running it in an emulator? Maybe the device has some kind of problem. I remember seeing this error too but I don't remember how I fixed it 😅

varunsinghNW18 commented 2 years ago

Thanks, Nikolas for replying. I use two devices & an emulator. The problem is those two devices every time I run gives me the error code GOOGLE_SERVICE_UNAVAILABLE error don't know where it is coming from. I have already been given 12 days two fix it but really don't know anything about it. If you have seen this error please try to think about how did you fix it. I really appreciate your effort on your example which really worked fantastically but the same thing gives me one error every time as it does not enter onSuccess listener.

1nikolas commented 2 years ago

Okay I think I remembered. Is your app on Google Play right now?

androminor commented 2 years ago

Yes it is

1nikolas commented 2 years ago

Is the integrity enabled?

androminor commented 2 years ago

Play integrity is enabled on the Play console side and not on Cloud console because we want that the app should be downloaded from the Play store only

1nikolas commented 2 years ago

Google Cloud is unrelated to the app being downloaded outside Play Store. You'll have to link a Google Cloud project to Play Console and configure the Google Cloud project as in here https://github.com/1nikolas/play-integrity-checker-server#how-to-set-up-google-cloud

androminor commented 2 years ago

Hey Nikolas, I have linked already the google cloud project to the play store. And I followed your link earlier carefully still it is throwing the same problem

androminor commented 2 years ago

I have done uptill here also downloaded the json ---> Go to Keys -> Add Key -> Create new key. The json that downloads automactially is the json you need for the Environment Variable.

androminor commented 2 years ago

something like this :

"type": "service_account", "project_id": "money-control-361608", "private_key_id": "e1e58eda3a9a", "private_key": "-----BEGIN "

1nikolas commented 2 years ago

Have you tried doing a release build of your app? Theoretically if someone was to generate fake tokens for your app, they could have the debug signing (aka when you hit run) and have your tokens. So I think this requires a release build. But not 100% this is the problem you can try

androminor commented 2 years ago

Ok let me understand what you are trying to say.. but where should I put the json in which environment variable ?. I am using Mac

1nikolas commented 2 years ago

The json should be in the server not the app

androminor commented 2 years ago

oh ok that means the back end server file rite ? I will try making a signed release build I guess.but I am not sure if this .

androminor commented 2 years ago

Now I have created a signed release build of my app. What is the next step ?

1nikolas commented 2 years ago

sorry I don't know how to help you