1*ed3bd27bSEvan Baconimport rnFixture from '../../plugins/__tests__/fixtures/react-native-project'; 2082815dcSEvan Baconimport { format } from '../../utils/XML'; 3*ed3bd27bSEvan Baconimport * as XML from '../../utils/XML'; 4*ed3bd27bSEvan Baconimport { AndroidManifest } from '../Manifest'; 5082815dcSEvan Baconimport { 6082815dcSEvan Bacon addBlockedPermissions, 7082815dcSEvan Bacon ensurePermission, 8082815dcSEvan Bacon ensurePermissions, 9082815dcSEvan Bacon getAndroidPermissions, 10082815dcSEvan Bacon getPermissions, 11082815dcSEvan Bacon removePermissions, 12082815dcSEvan Bacon setAndroidPermissions, 13082815dcSEvan Bacon withInternalBlockedPermissions, 14082815dcSEvan Bacon} from '../Permissions'; 15082815dcSEvan Bacon 16*ed3bd27bSEvan Baconasync function getFixtureManifestAsync() { 17*ed3bd27bSEvan Bacon const manifest = (await XML.parseXMLAsync( 18*ed3bd27bSEvan Bacon rnFixture['android/app/src/main/AndroidManifest.xml'] 19*ed3bd27bSEvan Bacon )) as AndroidManifest; 20082815dcSEvan Bacon 21*ed3bd27bSEvan Bacon removePermissions(manifest, [ 22*ed3bd27bSEvan Bacon 'android.permission.SYSTEM_ALERT_WINDOW', 23*ed3bd27bSEvan Bacon 'android.permission.VIBRATE', 24*ed3bd27bSEvan Bacon 'android.permission.READ_EXTERNAL_STORAGE', 25*ed3bd27bSEvan Bacon 'android.permission.WRITE_EXTERNAL_STORAGE', 26*ed3bd27bSEvan Bacon ]); 27*ed3bd27bSEvan Bacon return manifest; 28082815dcSEvan Bacon} 29082815dcSEvan Bacon 30082815dcSEvan Bacondescribe(withInternalBlockedPermissions, () => { 31082815dcSEvan Bacon it(`adds blocked permissions`, async () => { 32082815dcSEvan Bacon const config = withInternalBlockedPermissions({ 33082815dcSEvan Bacon slug: '', 34082815dcSEvan Bacon name: '', 35082815dcSEvan Bacon android: { 36082815dcSEvan Bacon blockedPermissions: ['android.permission.ACCESS_FINE_LOCATION', 'OTHER'], 37082815dcSEvan Bacon }, 38082815dcSEvan Bacon }); 39082815dcSEvan Bacon 40082815dcSEvan Bacon const { modResults } = await (config as any).mods.android.manifest({ 41082815dcSEvan Bacon modRequest: {}, 42*ed3bd27bSEvan Bacon modResults: await getFixtureManifestAsync(), 43082815dcSEvan Bacon }); 44082815dcSEvan Bacon 45082815dcSEvan Bacon expect(modResults).toEqual({ 46082815dcSEvan Bacon manifest: { 47082815dcSEvan Bacon $: { 48082815dcSEvan Bacon 'xmlns:android': expect.any(String), 49082815dcSEvan Bacon // Added tools 50082815dcSEvan Bacon 'xmlns:tools': 'http://schemas.android.com/tools', 51082815dcSEvan Bacon }, 52082815dcSEvan Bacon 'uses-permission': [ 53082815dcSEvan Bacon expect.anything(), 54082815dcSEvan Bacon // Added two blocked permissions 55082815dcSEvan Bacon { 56082815dcSEvan Bacon $: { 57082815dcSEvan Bacon 'android:name': 'android.permission.ACCESS_FINE_LOCATION', 58082815dcSEvan Bacon 'tools:node': 'remove', 59082815dcSEvan Bacon }, 60082815dcSEvan Bacon }, 61082815dcSEvan Bacon { 62082815dcSEvan Bacon $: { 638828a4a3SCedric van Putten 'android:name': 'android.permission.OTHER', 64082815dcSEvan Bacon 'tools:node': 'remove', 65082815dcSEvan Bacon }, 66082815dcSEvan Bacon }, 67082815dcSEvan Bacon ], 68082815dcSEvan Bacon queries: expect.anything(), 69082815dcSEvan Bacon application: expect.anything(), 70082815dcSEvan Bacon }, 71082815dcSEvan Bacon }); 72082815dcSEvan Bacon }); 73082815dcSEvan Bacon 74082815dcSEvan Bacon it(`does not add tools if there are no blocked permissions`, async () => { 75082815dcSEvan Bacon const config = withInternalBlockedPermissions({ 76082815dcSEvan Bacon slug: '', 77082815dcSEvan Bacon name: '', 78082815dcSEvan Bacon android: { 79082815dcSEvan Bacon blockedPermissions: [], 80082815dcSEvan Bacon }, 81082815dcSEvan Bacon }); 82082815dcSEvan Bacon 83082815dcSEvan Bacon // Doesn't even add the mod 84082815dcSEvan Bacon expect((config as any).mods).not.toBeDefined(); 85082815dcSEvan Bacon }); 868828a4a3SCedric van Putten 878828a4a3SCedric van Putten it(`adds blocked permission when using short notation`, async () => { 888828a4a3SCedric van Putten const config = withInternalBlockedPermissions({ 898828a4a3SCedric van Putten slug: '', 908828a4a3SCedric van Putten name: '', 918828a4a3SCedric van Putten android: { 928828a4a3SCedric van Putten permissions: ['android.permission.ACCESS_FINE_LOCATION'], 938828a4a3SCedric van Putten blockedPermissions: ['ACCESS_FINE_LOCATION'], 948828a4a3SCedric van Putten }, 958828a4a3SCedric van Putten }); 968828a4a3SCedric van Putten 978828a4a3SCedric van Putten const { modResults } = await (config as any).mods.android.manifest({ 988828a4a3SCedric van Putten modRequest: {}, 99*ed3bd27bSEvan Bacon modResults: await getFixtureManifestAsync(), 1008828a4a3SCedric van Putten }); 1018828a4a3SCedric van Putten 1028828a4a3SCedric van Putten expect(modResults).toEqual({ 1038828a4a3SCedric van Putten manifest: { 1048828a4a3SCedric van Putten $: { 1058828a4a3SCedric van Putten 'xmlns:android': expect.any(String), 1068828a4a3SCedric van Putten // Added tools 1078828a4a3SCedric van Putten 'xmlns:tools': 'http://schemas.android.com/tools', 1088828a4a3SCedric van Putten }, 1098828a4a3SCedric van Putten 'uses-permission': [ 1108828a4a3SCedric van Putten expect.anything(), 111*ed3bd27bSEvan Bacon 1128828a4a3SCedric van Putten // Added two blocked permissions 1138828a4a3SCedric van Putten { 1148828a4a3SCedric van Putten $: { 1158828a4a3SCedric van Putten 'android:name': 'android.permission.ACCESS_FINE_LOCATION', 1168828a4a3SCedric van Putten 'tools:node': 'remove', 1178828a4a3SCedric van Putten }, 1188828a4a3SCedric van Putten }, 1198828a4a3SCedric van Putten ], 1208828a4a3SCedric van Putten queries: expect.anything(), 1218828a4a3SCedric van Putten application: expect.anything(), 1228828a4a3SCedric van Putten }, 1238828a4a3SCedric van Putten }); 1248828a4a3SCedric van Putten }); 1258828a4a3SCedric van Putten 1268828a4a3SCedric van Putten it(`adds blocked permission when using long notation`, async () => { 1278828a4a3SCedric van Putten const config = withInternalBlockedPermissions({ 1288828a4a3SCedric van Putten slug: '', 1298828a4a3SCedric van Putten name: '', 1308828a4a3SCedric van Putten android: { 1318828a4a3SCedric van Putten permissions: ['ACCESS_FINE_LOCATION'], 1328828a4a3SCedric van Putten blockedPermissions: ['android.permission.ACCESS_FINE_LOCATION'], 1338828a4a3SCedric van Putten }, 1348828a4a3SCedric van Putten }); 1358828a4a3SCedric van Putten 1368828a4a3SCedric van Putten const { modResults } = await (config as any).mods.android.manifest({ 1378828a4a3SCedric van Putten modRequest: {}, 138*ed3bd27bSEvan Bacon modResults: await getFixtureManifestAsync(), 1398828a4a3SCedric van Putten }); 1408828a4a3SCedric van Putten 1418828a4a3SCedric van Putten expect(modResults).toEqual({ 1428828a4a3SCedric van Putten manifest: { 1438828a4a3SCedric van Putten $: { 1448828a4a3SCedric van Putten 'xmlns:android': expect.any(String), 1458828a4a3SCedric van Putten // Added tools 1468828a4a3SCedric van Putten 'xmlns:tools': 'http://schemas.android.com/tools', 1478828a4a3SCedric van Putten }, 1488828a4a3SCedric van Putten 'uses-permission': [ 1498828a4a3SCedric van Putten expect.anything(), 1508828a4a3SCedric van Putten // Added two blocked permissions 1518828a4a3SCedric van Putten { 1528828a4a3SCedric van Putten $: { 1538828a4a3SCedric van Putten 'android:name': 'android.permission.ACCESS_FINE_LOCATION', 1548828a4a3SCedric van Putten 'tools:node': 'remove', 1558828a4a3SCedric van Putten }, 1568828a4a3SCedric van Putten }, 1578828a4a3SCedric van Putten ], 1588828a4a3SCedric van Putten queries: expect.anything(), 1598828a4a3SCedric van Putten application: expect.anything(), 1608828a4a3SCedric van Putten }, 1618828a4a3SCedric van Putten }); 1628828a4a3SCedric van Putten }); 163082815dcSEvan Bacon}); 164082815dcSEvan Bacon 165082815dcSEvan Bacondescribe(addBlockedPermissions, () => { 166082815dcSEvan Bacon it(`restricts an existing permission`, () => { 167082815dcSEvan Bacon expect( 168082815dcSEvan Bacon addBlockedPermissions( 169082815dcSEvan Bacon { 170082815dcSEvan Bacon manifest: { 171082815dcSEvan Bacon $: { 172082815dcSEvan Bacon 'xmlns:android': '...', 173082815dcSEvan Bacon }, 174082815dcSEvan Bacon 'uses-permission': [ 175082815dcSEvan Bacon { 1768828a4a3SCedric van Putten $: { 'android:name': 'dev.expo.foobar' }, 177082815dcSEvan Bacon }, 178082815dcSEvan Bacon { 1798828a4a3SCedric van Putten $: { 'android:name': 'dev.expo.foobar-2' }, 180082815dcSEvan Bacon }, 181082815dcSEvan Bacon ], 182082815dcSEvan Bacon }, 183082815dcSEvan Bacon }, 1848828a4a3SCedric van Putten ['dev.expo.foobar'] 185082815dcSEvan Bacon ).manifest['uses-permission'] 186082815dcSEvan Bacon ).toStrictEqual([ 187082815dcSEvan Bacon { 1888828a4a3SCedric van Putten $: { 'android:name': 'dev.expo.foobar-2' }, 189082815dcSEvan Bacon }, 190082815dcSEvan Bacon { 1918828a4a3SCedric van Putten $: { 'android:name': 'dev.expo.foobar', 'tools:node': 'remove' }, 192082815dcSEvan Bacon }, 193082815dcSEvan Bacon ]); 194082815dcSEvan Bacon }); 195082815dcSEvan Bacon 196082815dcSEvan Bacon it(`restricts a new permission`, () => { 197082815dcSEvan Bacon expect( 198082815dcSEvan Bacon addBlockedPermissions( 199082815dcSEvan Bacon { 200082815dcSEvan Bacon manifest: { 201082815dcSEvan Bacon $: { 202082815dcSEvan Bacon 'xmlns:android': '...', 203082815dcSEvan Bacon }, 204082815dcSEvan Bacon 'uses-permission': [], 205082815dcSEvan Bacon }, 206082815dcSEvan Bacon }, 2078828a4a3SCedric van Putten ['dev.expo.foobar'] 208082815dcSEvan Bacon ).manifest['uses-permission'] 209082815dcSEvan Bacon ).toStrictEqual([ 210082815dcSEvan Bacon { 2118828a4a3SCedric van Putten $: { 'android:name': 'dev.expo.foobar', 'tools:node': 'remove' }, 212082815dcSEvan Bacon }, 213082815dcSEvan Bacon ]); 214082815dcSEvan Bacon }); 215082815dcSEvan Bacon}); 216082815dcSEvan Bacon 217082815dcSEvan Bacondescribe('Android permissions', () => { 218082815dcSEvan Bacon it(`returns empty array if no android permissions key is provided`, () => { 219082815dcSEvan Bacon expect(getAndroidPermissions({})).toMatchObject([]); 220082815dcSEvan Bacon }); 221082815dcSEvan Bacon 222082815dcSEvan Bacon it(`returns android permissions if array is provided`, () => { 223082815dcSEvan Bacon expect( 224082815dcSEvan Bacon getAndroidPermissions({ android: { permissions: ['CAMERA', 'RECORD_AUDIO'] } }) 225082815dcSEvan Bacon ).toMatchObject(['CAMERA', 'RECORD_AUDIO']); 226082815dcSEvan Bacon }); 227082815dcSEvan Bacon 228082815dcSEvan Bacon it('adds permissions if not present, does not duplicate permissions', async () => { 229082815dcSEvan Bacon const givenPermissions = [ 230082815dcSEvan Bacon 'android.permission.READ_CONTACTS', 231082815dcSEvan Bacon 'com.android.launcher.permission.INSTALL_SHORTCUT', 232082815dcSEvan Bacon 'com.android.launcher.permission.INSTALL_SHORTCUT', 233082815dcSEvan Bacon ]; 234*ed3bd27bSEvan Bacon let androidManifestJson = await getFixtureManifestAsync(); 235082815dcSEvan Bacon androidManifestJson = await setAndroidPermissions( 236082815dcSEvan Bacon { android: { permissions: givenPermissions } }, 237082815dcSEvan Bacon androidManifestJson 238082815dcSEvan Bacon ); 239082815dcSEvan Bacon 240082815dcSEvan Bacon const manifestPermissionsJSON = androidManifestJson.manifest['uses-permission']; 241*ed3bd27bSEvan Bacon const manifestPermissions = manifestPermissionsJSON!.map((e) => e.$['android:name']); 242082815dcSEvan Bacon 243082815dcSEvan Bacon // Account for INTERNET permission in fixture 244082815dcSEvan Bacon // No duplicates 245082815dcSEvan Bacon expect(manifestPermissions).toStrictEqual([ 246082815dcSEvan Bacon 'android.permission.INTERNET', 247*ed3bd27bSEvan Bacon 248082815dcSEvan Bacon 'android.permission.READ_CONTACTS', 249082815dcSEvan Bacon 'com.android.launcher.permission.INSTALL_SHORTCUT', 250082815dcSEvan Bacon ]); 251082815dcSEvan Bacon expect( 252082815dcSEvan Bacon manifestPermissions.filter((e) => e === 'com.android.launcher.permission.INSTALL_SHORTCUT') 253082815dcSEvan Bacon ).toHaveLength(1); 254082815dcSEvan Bacon }); 255082815dcSEvan Bacon}); 256082815dcSEvan Bacon 257082815dcSEvan Bacondescribe('Permissions', () => { 258082815dcSEvan Bacon it(`adds a new permission`, async () => { 259*ed3bd27bSEvan Bacon const manifest = await getFixtureManifestAsync(); 260082815dcSEvan Bacon const didAdd = ensurePermission(manifest, 'EXPO_TEST_PERMISSION'); 261082815dcSEvan Bacon const permissions = getPermissions(manifest); 262082815dcSEvan Bacon expect(didAdd).toBe(true); 263082815dcSEvan Bacon expect(permissions).toContain('android.permission.EXPO_TEST_PERMISSION'); 264082815dcSEvan Bacon expect(permissions.length).toBe(2); 265082815dcSEvan Bacon }); 266082815dcSEvan Bacon 267082815dcSEvan Bacon it(`prevents adding a duplicate permission`, async () => { 268*ed3bd27bSEvan Bacon const manifest = await getFixtureManifestAsync(); 269082815dcSEvan Bacon const didAdd = ensurePermission(manifest, 'INTERNET'); 270082815dcSEvan Bacon const permissions = getPermissions(manifest); 271082815dcSEvan Bacon expect(didAdd).toBe(false); 272082815dcSEvan Bacon expect(permissions).toContain('android.permission.INTERNET'); 273082815dcSEvan Bacon expect(permissions.length).toBe(1); 274082815dcSEvan Bacon }); 275082815dcSEvan Bacon 276082815dcSEvan Bacon it(`ensures multiple permissions`, async () => { 277*ed3bd27bSEvan Bacon const manifest = await getFixtureManifestAsync(); 278082815dcSEvan Bacon const permissionsToAdd = ['VALUE_1', 'VALUE_2']; 279082815dcSEvan Bacon const results = ensurePermissions(manifest, permissionsToAdd); 280082815dcSEvan Bacon expect(results).toMatchSnapshot(); 281082815dcSEvan Bacon expect(Object.values(results)).toStrictEqual([true, true]); 282082815dcSEvan Bacon 283082815dcSEvan Bacon expect(getPermissions(manifest).length).toBe(3); 284082815dcSEvan Bacon }); 285082815dcSEvan Bacon 286082815dcSEvan Bacon it(`removes permissions by name`, async () => { 287*ed3bd27bSEvan Bacon const manifest = await getFixtureManifestAsync(); 288082815dcSEvan Bacon expect(ensurePermission(manifest, 'VALUE_TO_REMOVE_1')).toBe(true); 289082815dcSEvan Bacon expect(ensurePermission(manifest, 'VALUE_TO_REMOVE_2')).toBe(true); 290082815dcSEvan Bacon expect(getPermissions(manifest).length).toBe(3); 291082815dcSEvan Bacon 292082815dcSEvan Bacon removePermissions(manifest, ['VALUE_TO_REMOVE_1', 'VALUE_TO_REMOVE_2']); 293082815dcSEvan Bacon expect(getPermissions(manifest).length).toBe(1); 294082815dcSEvan Bacon }); 295082815dcSEvan Bacon 296082815dcSEvan Bacon it(`removes all permissions`, async () => { 297*ed3bd27bSEvan Bacon const manifest = await getFixtureManifestAsync(); 298082815dcSEvan Bacon expect(ensurePermission(manifest, 'VALUE_TO_REMOVE_1')).toBe(true); 299082815dcSEvan Bacon expect(ensurePermission(manifest, 'VALUE_TO_REMOVE_2')).toBe(true); 300082815dcSEvan Bacon expect(getPermissions(manifest).length).toBe(3); 301082815dcSEvan Bacon 302082815dcSEvan Bacon removePermissions(manifest); 303082815dcSEvan Bacon 304082815dcSEvan Bacon expect(getPermissions(manifest).length).toBe(0); 305082815dcSEvan Bacon }); 306082815dcSEvan Bacon 307082815dcSEvan Bacon it(`can write with a pretty format`, async () => { 308*ed3bd27bSEvan Bacon const manifest = await getFixtureManifestAsync(); 309082815dcSEvan Bacon expect(ensurePermission(manifest, 'NEW_PERMISSION_1')).toBe(true); 310082815dcSEvan Bacon expect(ensurePermission(manifest, 'NEW_PERMISSION_2')).toBe(true); 311082815dcSEvan Bacon expect(getPermissions(manifest).length).toBe(3); 312082815dcSEvan Bacon 313082815dcSEvan Bacon expect(format(manifest)).toMatchSnapshot(); 314082815dcSEvan Bacon }); 315082815dcSEvan Bacon}); 316