Home | History | Annotate | Download | only in local
      1 /*
      2  * Copyright (C) 2017 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 package com.example.android.autofill.service.data.source.local;
     17 
     18 import android.content.pm.PackageInfo;
     19 import android.content.pm.PackageManager;
     20 import android.support.annotation.NonNull;
     21 
     22 import com.example.android.autofill.service.data.DataCallback;
     23 import com.example.android.autofill.service.data.source.DalService;
     24 import com.example.android.autofill.service.data.source.DigitalAssetLinksDataSource;
     25 import com.example.android.autofill.service.model.DalCheck;
     26 import com.example.android.autofill.service.model.DalInfo;
     27 import com.example.android.autofill.service.util.SecurityHelper;
     28 import com.google.common.net.InternetDomainName;
     29 
     30 import java.util.HashMap;
     31 
     32 import retrofit2.Call;
     33 import retrofit2.Callback;
     34 import retrofit2.Response;
     35 import retrofit2.Retrofit;
     36 
     37 import static com.example.android.autofill.service.util.Util.DalCheckRequirement;
     38 import static com.example.android.autofill.service.util.Util.DalCheckRequirement.AllUrls;
     39 import static com.example.android.autofill.service.util.Util.DalCheckRequirement.Disabled;
     40 import static com.example.android.autofill.service.util.Util.DalCheckRequirement.LoginOnly;
     41 import static com.example.android.autofill.service.util.Util.logd;
     42 
     43 
     44 /**
     45  * Singleton repository that caches the result of Digital Asset Links checks.
     46  */
     47 public class DigitalAssetLinksRepository implements DigitalAssetLinksDataSource {
     48     private static final String DAL_BASE_URL = "https://digitalassetlinks.googleapis.com";
     49     private static final String PERMISSION_GET_LOGIN_CREDS = "common.get_login_creds";
     50     private static final String PERMISSION_HANDLE_ALL_URLS = "common.handle_all_urls";
     51     private static DigitalAssetLinksRepository sInstance;
     52 
     53     private final PackageManager mPackageManager;
     54     private final DalService mDalService;
     55     private final HashMap<DalInfo, DalCheck> mCache;
     56 
     57     private DigitalAssetLinksRepository(PackageManager packageManager) {
     58         mPackageManager = packageManager;
     59         mCache = new HashMap<>();
     60         mDalService = new Retrofit.Builder()
     61                 .baseUrl(DAL_BASE_URL)
     62                 .build()
     63                 .create(DalService.class);
     64     }
     65 
     66     public static DigitalAssetLinksRepository getInstance(PackageManager packageManager) {
     67         if (sInstance == null) {
     68             sInstance = new DigitalAssetLinksRepository(packageManager);
     69         }
     70         return sInstance;
     71     }
     72 
     73     public static String getCanonicalDomain(String domain) {
     74         InternetDomainName idn = InternetDomainName.from(domain);
     75         while (idn != null && !idn.isTopPrivateDomain()) {
     76             idn = idn.parent();
     77         }
     78         return idn == null ? null : idn.toString();
     79     }
     80 
     81     @Override
     82     public void clear() {
     83         mCache.clear();
     84     }
     85 
     86     public void checkValid(DalCheckRequirement dalCheckRequirement, DalInfo dalInfo,
     87             DataCallback<DalCheck> dalCheckDataCallback) {
     88         if (dalCheckRequirement.equals(Disabled)) {
     89             DalCheck dalCheck = new DalCheck();
     90             dalCheck.linked = true;
     91             dalCheckDataCallback.onLoaded(dalCheck);
     92             return;
     93         }
     94 
     95         DalCheck dalCheck = mCache.get(dalInfo);
     96         if (dalCheck != null) {
     97             dalCheckDataCallback.onLoaded(dalCheck);
     98             return;
     99         }
    100         String packageName = dalInfo.getPackageName();
    101         String webDomain = dalInfo.getWebDomain();
    102 
    103         final String fingerprint;
    104         try {
    105             PackageInfo packageInfo = mPackageManager.getPackageInfo(packageName,
    106                     PackageManager.GET_SIGNATURES);
    107             fingerprint = SecurityHelper.getFingerprint(packageInfo, packageName);
    108         } catch (Exception e) {
    109             dalCheckDataCallback.onDataNotAvailable("Error getting fingerprint for %s",
    110                     packageName);
    111             return;
    112         }
    113         logd("validating domain %s for pkg %s and fingerprint %s.", webDomain,
    114                 packageName, fingerprint);
    115         mDalService.check(webDomain, PERMISSION_GET_LOGIN_CREDS, packageName, fingerprint).enqueue(
    116                 new Callback<DalCheck>() {
    117                     @Override
    118                     public void onResponse(@NonNull Call<DalCheck> call,
    119                             @NonNull Response<DalCheck> response) {
    120                         DalCheck dalCheck = response.body();
    121                         if (dalCheck == null || !dalCheck.linked) {
    122                             // get_login_creds check failed, so try handle_all_urls check
    123                             if (dalCheckRequirement.equals(LoginOnly)) {
    124                                 dalCheckDataCallback.onDataNotAvailable(
    125                                         "DAL: Login creds check failed.");
    126                             } else if (dalCheckRequirement.equals(AllUrls)) {
    127                                 mDalService.check(webDomain, PERMISSION_HANDLE_ALL_URLS,
    128                                         packageName, fingerprint).enqueue(new Callback<DalCheck>() {
    129                                     @Override
    130                                     public void onResponse(@NonNull Call<DalCheck> call,
    131                                             @NonNull Response<DalCheck> response) {
    132                                         DalCheck dalCheck = response.body();
    133                                         mCache.put(dalInfo, dalCheck);
    134                                         dalCheckDataCallback.onLoaded(dalCheck);
    135                                     }
    136 
    137                                     @Override
    138                                     public void onFailure(@NonNull Call<DalCheck> call,
    139                                             @NonNull Throwable t) {
    140                                         dalCheckDataCallback.onDataNotAvailable(t.getMessage());
    141                                     }
    142                                 });
    143                             }
    144                         } else {
    145                             // get_login_creds check succeeded, so we're finished.
    146                             mCache.put(dalInfo, dalCheck);
    147                             dalCheckDataCallback.onLoaded(dalCheck);
    148                         }
    149                     }
    150 
    151                     @Override
    152                     public void onFailure(@NonNull Call<DalCheck> call, @NonNull Throwable t) {
    153                         // get_login_creds check failed, so try handle_all_urls check.
    154                         mDalService.check(webDomain, PERMISSION_HANDLE_ALL_URLS, packageName,
    155                                 fingerprint);
    156                     }
    157                 });
    158     }
    159 }
    160