Esempio n. 1
0
    It's safer/easier to generate an app password and
    use it instead of the actual password.
    It still has the same access as the regular password,
    but still better than using the real password while scripting.
    (https://myaccount.google.com/apppasswords)
    """
    )

    # Using google username and password
    client = GLocalAuthenticationTokens(
        username=GOOGLE_USERNAME,
        password=GOOGLE_PASSWORD,
        master_token=GOOGLE_MASTER_TOKEN,
        android_id=DEVICE_ID,
        verbose=True,
    )

    # Get master token
    print("[*] Master token", client.get_master_token())

    # Get access token (lives 1 hour)
    print("\n[*] Access token (lives 1 hour)", client.get_access_token())

    # Get google device local authentication tokens (live about 1 day)
    print("\n[*] Google devices local authentication tokens")
    google_devices = client.get_google_devices_json()
    # Pretty print json data
    google_devices_str = json.dumps(google_devices, indent=2)
    print("[*] Google devices", google_devices_str)
Esempio n. 2
0
class GLocalAuthenticationTokensClientTests(DeviceAssertions, TypeAssertions,
                                            TestCase):
    def setUp(self):
        """Setup method run before every test"""
        self.client = GLocalAuthenticationTokens(username=faker.word(),
                                                 password=faker.word())

    def tearDown(self):
        """Teardown method run after every test"""
        pass

    def test_initialization(self):
        username = faker.word()
        password = faker.word()
        master_token = faker.master_token()
        android_id = faker.word()

        client = GLocalAuthenticationTokens(
            username=username,
            password=password,
            master_token=master_token,
            android_id=android_id,
        )
        self.assertEqual(username, client.username)
        self.assertEqual(password, client.password)
        self.assertEqual(master_token, client.master_token)
        self.assertEqual(android_id, client.android_id)

        self.assertIsString(client.username)
        self.assertIsString(client.password)
        self.assertIsString(client.master_token)
        self.assertIsString(client.android_id)

        self.assertIsNone(client.access_token)
        self.assertIsNone(client.homegraph)
        self.assertIsNone(client.access_token_date)
        self.assertIsNone(client.homegraph_date)

        self.assertIsAASET(client.master_token)

    @patch("glocaltokens.client.LOGGER.error")
    def test_initialization__valid(self, m_log):
        # With username and password
        GLocalAuthenticationTokens(username=faker.word(),
                                   password=faker.word())
        self.assertEqual(m_log.call_count, 0)

        # With master_token
        GLocalAuthenticationTokens(master_token=faker.master_token())
        self.assertEqual(m_log.call_count, 0)

    @patch("glocaltokens.client.LOGGER.setLevel")
    def test_initialization__valid_verbose_logger(self, m_set_level):
        # Non verbose
        GLocalAuthenticationTokens(username=faker.word(),
                                   password=faker.word())
        self.assertEqual(m_set_level.call_count, 0)

        # Verbose
        GLocalAuthenticationTokens(username=faker.word(),
                                   password=faker.word(),
                                   verbose=True)
        m_set_level.assert_called_once_with(logging.DEBUG)

    @patch("glocaltokens.client.LOGGER.error")
    def test_initialization__invalid(self, m_log):
        # Without username
        GLocalAuthenticationTokens(password=faker.word())
        self.assertEqual(m_log.call_count, 1)

        # Without password
        GLocalAuthenticationTokens(username=faker.word())
        self.assertEqual(m_log.call_count, 2)

        # Without username and password
        GLocalAuthenticationTokens()
        self.assertEqual(m_log.call_count, 3)

        # With invalid master_token
        GLocalAuthenticationTokens(master_token=faker.word())
        self.assertEqual(m_log.call_count, 4)

    def test_get_android_id(self):
        android_id = self.client.get_android_id()
        self.assertTrue(len(android_id) == ANDROID_ID_LENGTH)

        self.assertIsString(android_id)

        # Make sure we get the same ID when called further
        self.assertEqual(android_id, self.client.get_android_id())

    def test_generate_mac_string(self):
        mac_string = GLocalAuthenticationTokens._generate_mac_string()
        self.assertTrue(len(mac_string) == ANDROID_ID_LENGTH)

        # Make sure we get different generated mac string
        self.assertNotEqual(mac_string,
                            GLocalAuthenticationTokens._generate_mac_string())

    def test_has_expired(self):
        duration_sec = 60
        now = datetime.now()
        token_dt__expired = now - timedelta(seconds=duration_sec + 1)
        token_dt__non_expired = now - timedelta(seconds=duration_sec - 1)

        # Expired
        self.assertTrue(
            GLocalAuthenticationTokens._has_expired(token_dt__expired,
                                                    duration_sec))

        # Non expired
        self.assertFalse(
            GLocalAuthenticationTokens._has_expired(token_dt__non_expired,
                                                    duration_sec))

    @patch("glocaltokens.client.LOGGER.error")
    @patch("glocaltokens.client.perform_master_login")
    def test_get_master_token(self, m_perform_master_login, m_log):
        # No token in response
        self.assertIsNone(self.client.get_master_token())
        m_perform_master_login.assert_called_once_with(
            self.client.username, self.client.password,
            self.client.get_android_id())
        self.assertEqual(m_log.call_count, 1)

        # Reset mocks
        m_perform_master_login.reset_mock()
        m_log.reset_mock()

        # With token in response
        expected_master_token = faker.master_token()
        m_perform_master_login.return_value = {"Token": expected_master_token}
        master_token = self.client.get_master_token()
        m_perform_master_login.assert_called_once_with(
            self.client.username, self.client.password,
            self.client.get_android_id())
        self.assertEqual(expected_master_token, master_token)
        self.assertEqual(m_log.call_count, 0)

        # Another request - must return the same token all the time
        master_token = self.client.get_master_token()
        self.assertEqual(expected_master_token, master_token)

    @patch("glocaltokens.client.LOGGER.error")
    @patch("glocaltokens.client.perform_master_login")
    @patch("glocaltokens.client.perform_oauth")
    def test_get_access_token(self, m_perform_oauth, m_get_master_token,
                              m_log):
        master_token = faker.master_token()
        m_get_master_token.return_value = {"Token": master_token}

        # No token in response
        self.assertIsNone(self.client.get_access_token())
        m_perform_oauth.assert_called_once_with(
            self.client.username,
            master_token,
            self.client.get_android_id(),
            app=ACCESS_TOKEN_APP_NAME,
            service=ACCESS_TOKEN_SERVICE,
            client_sig=ACCESS_TOKEN_CLIENT_SIGNATURE,
        )
        self.assertEqual(m_log.call_count, 1)

        # Reset mocks
        m_perform_oauth.reset_mock()
        m_log.reset_mock()

        # With token in response
        expected_access_token = faker.access_token()
        m_perform_oauth.return_value = {"Auth": expected_access_token}
        access_token = self.client.get_access_token()
        m_perform_oauth.assert_called_once_with(
            self.client.username,
            master_token,
            self.client.get_android_id(),
            app=ACCESS_TOKEN_APP_NAME,
            service=ACCESS_TOKEN_SERVICE,
            client_sig=ACCESS_TOKEN_CLIENT_SIGNATURE,
        )
        self.assertEqual(expected_access_token, access_token)
        self.assertEqual(m_log.call_count, 0)

        # Reset mocks
        m_perform_oauth.reset_mock()
        m_log.reset_mock()

        # Another request with non expired token must return the same token
        # (no new requests)
        access_token = self.client.get_access_token()
        self.assertEqual(expected_access_token, access_token)
        self.assertEqual(m_perform_oauth.call_count, 0)

        # Another request with expired token must return new token (new request)
        self.client.access_token_date = self.client.access_token_date - timedelta(
            ACCESS_TOKEN_DURATION + 1)
        access_token = self.client.get_access_token()
        self.assertEqual(m_perform_oauth.call_count, 1)

    @patch("glocaltokens.client.grpc.ssl_channel_credentials")
    @patch("glocaltokens.client.grpc.access_token_call_credentials")
    @patch("glocaltokens.client.grpc.composite_channel_credentials")
    @patch("glocaltokens.client.grpc.secure_channel")
    @patch("glocaltokens.client.v1_pb2_grpc.StructuresServiceStub")
    @patch("glocaltokens.client.v1_pb2.GetHomeGraphRequest")
    @patch("glocaltokens.client.GLocalAuthenticationTokens.get_access_token")
    def test_get_homegraph(
        self,
        m_get_access_token,
        m_get_home_graph_request,
        m_structure_service_stub,
        m_secure_channel,
        m_composite_channel_credentials,
        m_access_token_call_credentials,
        m_ssl_channel_credentials,
    ):
        # New homegraph
        self.client.get_homegraph()
        self.assertEqual(m_ssl_channel_credentials.call_count, 1)
        self.assertEqual(m_access_token_call_credentials.call_count, 1)
        self.assertEqual(m_composite_channel_credentials.call_count, 1)
        self.assertEqual(m_secure_channel.call_count, 1)
        self.assertEqual(m_structure_service_stub.call_count, 1)
        self.assertEqual(m_get_home_graph_request.call_count, 1)

        # Another request with non expired homegraph must return the same homegraph
        # (no new requests)
        self.client.get_homegraph()
        self.assertEqual(m_ssl_channel_credentials.call_count, 1)
        self.assertEqual(m_access_token_call_credentials.call_count, 1)
        self.assertEqual(m_composite_channel_credentials.call_count, 1)
        self.assertEqual(m_secure_channel.call_count, 1)
        self.assertEqual(m_structure_service_stub.call_count, 1)
        self.assertEqual(m_get_home_graph_request.call_count, 1)

        # Expired homegraph
        self.client.homegraph_date = self.client.homegraph_date - timedelta(
            HOMEGRAPH_DURATION + 1)
        self.client.get_homegraph()
        self.assertEqual(m_ssl_channel_credentials.call_count, 2)
        self.assertEqual(m_access_token_call_credentials.call_count, 2)
        self.assertEqual(m_composite_channel_credentials.call_count, 2)
        self.assertEqual(m_secure_channel.call_count, 2)
        self.assertEqual(m_structure_service_stub.call_count, 2)
        self.assertEqual(m_get_home_graph_request.call_count, 2)

    @patch("glocaltokens.client.GLocalAuthenticationTokens.get_homegraph")
    def test_get_google_devices(self, m_get_homegraph):
        # With just one device returned from homegraph
        homegraph_device = faker.homegraph_device()
        m_get_homegraph.return_value.home.devices = [homegraph_device]

        # With no discover_devices, with no model_list
        google_devices = self.client.get_google_devices(disable_discovery=True)
        self.assertEqual(len(google_devices), 1)

        google_device = google_devices[0]
        self.assertEqual(type(google_device), Device)
        self.assertDevice(google_device, homegraph_device)

        # With two devices returned from homegraph
        # but one device having the invalid token
        homegraph_device_valid = faker.homegraph_device()
        homegraph_device_invalid = faker.homegraph_device()
        homegraph_device_invalid.local_auth_token = (
            faker.word())  # setting invalid token intentionally
        # Note that we initialize the list with homegraph_device_invalid
        # which should be ignored
        m_get_homegraph.return_value.home.devices = [
            homegraph_device_invalid,
            homegraph_device_valid,
        ]
        google_devices = self.client.get_google_devices(disable_discovery=True)
        self.assertEqual(len(google_devices), 1)
        self.assertDevice(google_devices[0], homegraph_device_valid)

    @patch("glocaltokens.client.GLocalAuthenticationTokens.get_google_devices")
    def test_get_google_devices_json(self, m_get_google_devices):
        device_name = faker.word()
        local_auth_token = faker.local_auth_token()
        ip = faker.ipv4()
        port = faker.port_number()
        hardware = faker.word()
        google_device = Device(
            device_name=device_name,
            local_auth_token=local_auth_token,
            ip=ip,
            port=port,
            hardware=hardware,
        )
        m_get_google_devices.return_value = [google_device]

        json_string = self.client.get_google_devices_json(
            disable_discovery=True)
        self.assertEqual(m_get_google_devices.call_count, 1)
        self.assertIsString(json_string)
        received_json = json.loads(json_string)
        received_device = received_json[0]
        self.assertEqual(received_device[JSON_KEY_DEVICE_NAME], device_name)
        self.assertEqual(received_device[JSON_KEY_HARDWARE], hardware)
        self.assertEqual(received_device[JSON_KEY_LOCAL_AUTH_TOKEN],
                         local_auth_token)
        self.assertEqual(
            received_device[JSON_KEY_GOOGLE_DEVICE][JSON_KEY_PORT], port)
        self.assertEqual(received_device[JSON_KEY_GOOGLE_DEVICE][JSON_KEY_IP],
                         ip)