1 /*
2  * Copyright (C) 2023 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 
17 package com.android.server.wifi.entitlement.response;
18 
19 import static android.text.format.DateUtils.HOUR_IN_MILLIS;
20 
21 import android.text.TextUtils;
22 import android.util.Log;
23 
24 import com.android.internal.annotations.VisibleForTesting;
25 import com.android.server.wifi.entitlement.PseudonymInfo;
26 import com.android.server.wifi.entitlement.RequestFactory;
27 
28 import org.json.JSONArray;
29 import org.json.JSONException;
30 import org.json.JSONObject;
31 
32 import java.util.Optional;
33 
34 
35 /** The response of get IMSI pseudonym request */
36 public class GetImsiPseudonymResponse extends Response {
37     private static final String TAG = "WifiEntitlement(GetImsiPseudonymResponse)";
38     @VisibleForTesting
39     static final String JSON_KEY_IMSI_PSEUDONYM = "imsi-pseudonym";
40     @VisibleForTesting
41     public static final String JSON_KEY_REFRESH_INTERVAL = "refresh-interval";
42 
43     // Refer to https://www.rfc-editor.org/rfc/rfc3748#section-3.1
44     private static final int EAP_MTU = 1020;
45     private int mGetImsiPseudonymResponseCode;
46     private int mRefreshInterval;
47     private String mImsiPseudonym;
48 
GetImsiPseudonymResponse(String responseBody)49     public GetImsiPseudonymResponse(String responseBody) {
50         if (TextUtils.isEmpty(responseBody)) {
51             Log.e(TAG, "Error! Empty responseBody!");
52             return;
53         }
54         try {
55             JSONArray array = new JSONArray(responseBody);
56             for (int i = 0; i < array.length(); i++) {
57                 JSONObject object = array.optJSONObject(i);
58                 if (object == null) {
59                     continue;
60                 }
61                 int id = object.optInt(JSON_KEY_MESSAGE_ID, -1);
62                 switch (id) {
63                     case RequestFactory.MESSAGE_ID_3GPP_AUTHENTICATION:
64                         parse3gppAuthentication(object);
65                         break;
66                     case RequestFactory.MESSAGE_ID_GET_IMSI_PSEUDONYM:
67                         parseGetImsiPseudonym(object);
68                         break;
69                     default:
70                         Log.e(TAG, "Unexpected Message ID >> " + id);
71                 }
72             }
73         } catch (JSONException e) {
74             Log.e(TAG, "ERROR! not a valid JSONArray String![" + responseBody + "]", e);
75         }
76     }
77 
parseGetImsiPseudonym(JSONObject object)78     private void parseGetImsiPseudonym(JSONObject object) {
79         mGetImsiPseudonymResponseCode = object.optInt(JSON_KEY_RESPONSE_CODE, -1);
80         mImsiPseudonym = object.optString(JSON_KEY_IMSI_PSEUDONYM, null);
81         mRefreshInterval = object.optInt(JSON_KEY_REFRESH_INTERVAL, -1);
82     }
83 
84     /** Returns {@code PseudonymInfo} with server returned information. */
toPseudonymInfo(String imsi)85     public Optional<PseudonymInfo> toPseudonymInfo(String imsi) {
86         PseudonymInfo pseudonymInfo = null;
87         boolean success =
88                 (mAuthResponseCode == RESPONSE_CODE_REQUEST_SUCCESSFUL)
89                         && (mGetImsiPseudonymResponseCode == RESPONSE_CODE_REQUEST_SUCCESSFUL);
90         if (success && (mImsiPseudonym != null) && (mImsiPseudonym.length() <= EAP_MTU)) {
91             if (mRefreshInterval <= 0) {
92                 pseudonymInfo = new PseudonymInfo(mImsiPseudonym, imsi);
93             } else {
94                 pseudonymInfo = new PseudonymInfo(mImsiPseudonym, imsi,
95                         mRefreshInterval * HOUR_IN_MILLIS);
96             }
97         }
98         return Optional.ofNullable(pseudonymInfo);
99     }
100 
101     /** Returns AKA token. */
getAkaToken()102     public String getAkaToken() {
103         return mAkaToken;
104     }
105 
getGetImsiPseudonymResponseCode()106     public int getGetImsiPseudonymResponseCode() {
107         return mGetImsiPseudonymResponseCode;
108     }
109 }
110 
111