• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 package com.android.server.wifi.entitlement;
17 
18 import android.annotation.NonNull;
19 
20 import com.android.internal.annotations.VisibleForTesting;
21 
22 import java.time.Duration;
23 import java.time.Instant;
24 
25 /** The Imsi Pseudonym information*/
26 public class PseudonymInfo {
27     @VisibleForTesting
28     static final long DEFAULT_PSEUDONYM_TTL_IN_MILLIS = Duration.ofDays(2).toMillis();
29     @VisibleForTesting
30     static final long REFRESH_AHEAD_TIME_IN_MILLIS = Duration.ofMinutes(30).toMillis();
31     static final long MINIMUM_REFRESH_INTERVAL_IN_MILLIS = Duration.ofHours(12).toMillis();
32 
33     private final String mImsi;
34     private final String mPseudonym;
35 
36     /*
37      * The number of milliseconds from the epoch of 1970-01-01T00:00:00Z when the pseudonym is
38      * received.
39      */
40     private final long mTimeStamp;
41 
42     /*
43      * Time To Live in milliseconds from the pseudonym is received. This is the maximum lifetime of
44      * a pseudonym. The pseudonym remains valid from the time it is received, until the mTtlInMillis
45      * has elapsed.
46      */
47     private final long mTtlInMillis;
48 
49     /*
50      * Age To Refresh in milliseconds from the pseudonym is received. When a pseudonym is expiring,
51      * we should refresh it ahead of time. For example, we refresh a pseudonym half an hour before
52      * it expires. The TTL is 24 hours. So we should refresh this pseudonym when it is 23.5 hours
53      * old.
54      */
55     private final long mAtrInMillis;
56 
57     /*
58      * Minimum Age To Refresh in milliseconds from the pseudonym is received. We should not
59      * refresh the pseudonym too frequently.
60      */
61 
62     private final long mMinAtrInMillis;
63 
PseudonymInfo(@onNull String pseudonym, @NonNull String imsi)64     public PseudonymInfo(@NonNull String pseudonym, @NonNull String imsi) {
65         this(pseudonym, imsi, DEFAULT_PSEUDONYM_TTL_IN_MILLIS);
66     }
67 
PseudonymInfo(@onNull String pseudonym, @NonNull String imsi, long ttlInMillis)68     public PseudonymInfo(@NonNull String pseudonym, @NonNull String imsi, long ttlInMillis) {
69         this(pseudonym, imsi, ttlInMillis, Instant.now().toEpochMilli());
70     }
71 
72     @VisibleForTesting
PseudonymInfo(@onNull String pseudonym, @NonNull String imsi, long ttlInMillis, long timeStamp)73     public PseudonymInfo(@NonNull String pseudonym, @NonNull String imsi, long ttlInMillis,
74             long timeStamp) {
75         mPseudonym = pseudonym;
76         mImsi = imsi;
77         mTimeStamp = timeStamp;
78         mTtlInMillis = ttlInMillis;
79         mAtrInMillis = ttlInMillis - Math.min(ttlInMillis / 2, REFRESH_AHEAD_TIME_IN_MILLIS);
80         mMinAtrInMillis = Math.min(mAtrInMillis, MINIMUM_REFRESH_INTERVAL_IN_MILLIS);
81     }
82 
getPseudonym()83     public String getPseudonym() {
84         return mPseudonym;
85     }
86 
getImsi()87     public String getImsi() {
88         return mImsi;
89     }
90 
91     /**
92      * Returns the Time To Live in milliseconds.
93      */
getTtlInMillis()94     public long getTtlInMillis() {
95         return mTtlInMillis;
96     }
97 
98     /*
99      * Returns the Age To Refresh in milliseconds.
100      */
getAtrInMillis()101     public long getAtrInMillis() {
102         return mAtrInMillis;
103     }
104 
105     /**
106      * Returns whether the pseudonym has expired or not.
107      */
hasExpired()108     public boolean hasExpired() {
109         return Instant.now().toEpochMilli() - mTimeStamp >= mTtlInMillis;
110     }
111 
112     /**
113      * Returns whether the pseudonym should be refreshed. A pseudonym should be refreshed before
114      * it expires.
115      */
shouldBeRefreshed()116     public boolean shouldBeRefreshed() {
117         return (Instant.now().toEpochMilli() - mTimeStamp) >= mAtrInMillis;
118     }
119 
120     /**
121      * Returns whether the pseudonym is old enough to refresh. To prevent DOS attack, the pseudonym
122      * should not be refreshed too frequently.
123      */
isOldEnoughToRefresh()124     public boolean isOldEnoughToRefresh() {
125         return Instant.now().toEpochMilli() - mTimeStamp >= mMinAtrInMillis;
126     }
127 
128     @Override
toString()129     public String toString() {
130         // Mask the pseudonym and IMSI which are two kinds of PII.
131         return " mPseudonym="
132                 + (mPseudonym.length() >= 7 ? (mPseudonym.substring(0, 7) + "***") : mPseudonym)
133                 + " mImsi=***"
134                 + (mImsi.length() >= 3 ? mImsi.substring(mImsi.length() - 3) : mImsi)
135                 + " mTimeStamp=" + mTimeStamp
136                 + " mTtlInMillis=" + mTtlInMillis
137                 + " mTtrInMillis=" + mAtrInMillis
138                 + " mMinTtrInMillis=" + mMinAtrInMillis;
139     }
140 }
141