1 /* 2 * Copyright (C) 2024 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.nfc; 18 19 import static com.android.nfc.NfcWifiProtectedSetup.NFC_TOKEN_MIME_TYPE; 20 21 import static com.google.common.primitives.Bytes.concat; 22 23 import static org.mockito.ArgumentMatchers.eq; 24 import static org.mockito.Mockito.mock; 25 import static org.mockito.Mockito.spy; 26 import static org.mockito.Mockito.when; 27 28 import android.annotation.NonNull; 29 import android.annotation.Nullable; 30 import android.content.BroadcastReceiver; 31 import android.content.Context; 32 import android.content.ContextWrapper; 33 import android.content.Intent; 34 import android.content.IntentFilter; 35 import android.content.pm.PackageManager; 36 import android.content.res.Resources; 37 import android.net.wifi.WifiConfiguration; 38 import android.nfc.FormatException; 39 import android.nfc.NdefMessage; 40 import android.nfc.NdefRecord; 41 import android.nfc.tech.Ndef; 42 import android.os.Handler; 43 import android.os.PowerManager; 44 import android.util.Log; 45 46 import com.android.dx.mockito.inline.extended.ExtendedMockito; 47 48 import junit.framework.TestCase; 49 50 import org.junit.After; 51 import org.junit.Assert; 52 import org.junit.Before; 53 import org.junit.Test; 54 import org.junit.runner.RunWith; 55 import org.mockito.Mockito; 56 import org.mockito.MockitoSession; 57 import org.mockito.quality.Strictness; 58 59 import androidx.test.ext.junit.runners.AndroidJUnit4; 60 import androidx.test.platform.app.InstrumentationRegistry; 61 62 import java.nio.ByteBuffer; 63 64 65 @RunWith(AndroidJUnit4.class) 66 public class NfcWifiProtectedSetupTest extends TestCase { 67 68 private static final String TAG = NfcWifiProtectedSetupTest.class.getSimpleName(); 69 private boolean mNfcSupported; 70 private MockitoSession mStaticMockSession; 71 private Context mockContext; 72 public static final byte[] CREDENTIAL = {0x10, 0x0e}; 73 public static final byte[] NETWORK_IDX = {0x10, 0x26}; 74 public static final byte[] NETWORK_NAME = {0x10, 0x45}; 75 public static final byte[] AUTH_TYPE = {0x10, 0x03}; 76 public static final byte[] CRYPT_TYPE = {0x10, 0x0F}; 77 public static final byte[] AUTH_WPA_PERSONAL = {0x00, 0x02}; 78 public static final byte[] CRYPT_WEP = {0x00, 0x02}; 79 public static final byte[] CRYPT_AES_TKIP = {0x00, 0x0C}; 80 public static final byte[] NETWORK_KEY = {0x10, 0x27}; 81 public static final byte[] WPS_AUTH_WPA_PERSONAL = {0x00, 0x02}; 82 public static final byte[] MAC_ADDRESS = {0x10, 0x20}; 83 84 85 @Before setUp()86 public void setUp() throws Exception { 87 mStaticMockSession = ExtendedMockito.mockitoSession() 88 .mockStatic(Ndef.class) 89 .strictness(Strictness.LENIENT) 90 .startMocking(); 91 92 Context context = InstrumentationRegistry.getInstrumentation().getTargetContext(); 93 PackageManager pm = context.getPackageManager(); 94 if (!pm.hasSystemFeature(PackageManager.FEATURE_NFC_ANY)) { 95 mNfcSupported = false; 96 return; 97 } 98 mNfcSupported = true; 99 100 PowerManager mockPowerManager = Mockito.mock(PowerManager.class); 101 when(mockPowerManager.isInteractive()).thenReturn(false); 102 Resources mockResources = Mockito.mock(Resources.class); 103 when(mockResources.getBoolean(eq(R.bool.tag_intent_app_pref_supported))) 104 .thenReturn(false); 105 106 mockContext = new ContextWrapper(context) { 107 @Override 108 public Object getSystemService(String name) { 109 if (Context.POWER_SERVICE.equals(name)) { 110 Log.i(TAG, "[Mock] mockPowerManager"); 111 return mockPowerManager; 112 } 113 return super.getSystemService(name); 114 } 115 116 @Override 117 public Resources getResources() { 118 Log.i(TAG, "[Mock] getResources"); 119 return mockResources; 120 } 121 122 @Override 123 public Intent registerReceiverForAllUsers(@Nullable BroadcastReceiver receiver, 124 @NonNull IntentFilter filter, @Nullable String broadcastPermission, 125 @Nullable Handler scheduler) { 126 Log.i(TAG, "[Mock] getIntent"); 127 return Mockito.mock(Intent.class); 128 } 129 }; 130 } 131 132 @After tearDown()133 public void tearDown() throws Exception { 134 mStaticMockSession.finishMocking(); 135 } 136 137 @Test testTryNfcWifiSetupFailed()138 public void testTryNfcWifiSetupFailed() { 139 if (!mNfcSupported) return; 140 141 Ndef ndef = mock(Ndef.class); 142 NdefMessage ndefMessage = mock(NdefMessage.class); 143 144 NdefRecord[] ndefRecords = new NdefRecord[2]; 145 byte[] version = new byte[]{(0x1 << 4) | (0x2)}; 146 ndefRecords[0] = new NdefRecord(NdefRecord.TNF_WELL_KNOWN, 147 NdefRecord.RTD_HANDOVER_REQUEST, new byte[0], version); 148 ndefRecords[1] = createWifiRecord(new String[]{"Nfctest", "", "Open", "wet"}); 149 when(ndefMessage.getRecords()).thenReturn(ndefRecords); 150 when(ndef.getCachedNdefMessage()).thenReturn(ndefMessage); 151 boolean isSucceeded = NfcWifiProtectedSetup.tryNfcWifiSetup(ndef, mockContext); 152 Log.d(TAG, "testTryNfcWifiSetupFailed - " + isSucceeded); 153 Assert.assertFalse(isSucceeded); 154 } 155 createWifiRecord(String[] data)156 private NdefRecord createWifiRecord(String[] data) { 157 String ssid = data[0]; 158 String password = data[1]; 159 byte[] ssidByte = ssid.getBytes(); 160 byte[] passwordByte = password.getBytes(); 161 byte[] ssidLength = {(byte) ((int) Math.floor(ssid.length() / 256)), 162 (byte) (ssid.length() % 256)}; 163 byte[] passwordLength = {(byte) ((int) Math.floor(password.length() / 256)), 164 (byte) (password.length() % 256)}; 165 byte[] cred = {0x00, 0x36}; 166 byte[] idx = {0x00, 0x01, 0x01}; 167 byte[] mac = {}; 168 169 byte[] payload = concat(CREDENTIAL, cred, 170 NETWORK_IDX, idx, 171 NETWORK_NAME, ssidLength, ssidByte, 172 AUTH_TYPE, AUTH_WPA_PERSONAL, WPS_AUTH_WPA_PERSONAL, 173 CRYPT_TYPE, CRYPT_WEP, CRYPT_AES_TKIP, 174 NETWORK_KEY, passwordLength, passwordByte, 175 MAC_ADDRESS, mac); 176 return NdefRecord.createMime(NFC_TOKEN_MIME_TYPE, payload); 177 } 178 }