Exemplo n.º 1
0
def icloud_api():
    from pyicloud import PyiCloudService
    api = PyiCloudService('*****@*****.**', 'Div32190')
    if api.requires_2sa:
        import click
        print("Two-step authentication required. Your trusted devices are:")

        devices = api.trusted_devices
        for i, device in enumerate(devices):
            print("  %s: %s" %
                  (i,
                   device.get('deviceName',
                              "SMS to %s" % device.get('phoneNumber'))))

        device = click.prompt('Which device would you like to use?', default=0)
        device = devices[device]
        if not api.send_verification_code(device):
            print("Failed to send verification code")
            sys.exit(1)

        code = click.prompt('Please enter validation code')
        if not api.validate_verification_code(device, code):
            print("Failed to verify verification code")
            sys.exit(1)
    print(api.iphone.location())
    print("Files =============>", api.files.dir())
    print("Archives ==========>", api.archives.dir())
Exemplo n.º 2
0
    def _connect(user, password):
        """
        Connect to the icloud

        :param user: the icloud user id
        :param password: the icloud password
        :return a reference to the icloud
        """
        api = PyiCloudService(user, password)

        if api.requires_2sa:  # this attribute is added by the patched pyicloud at https://github.com/picklepete/pyicloud.git
            import click
            print(
                "Two-step authentication required. Your trusted devices are:")

            devices = api.trusted_devices
            for i, device in enumerate(devices):
                print("  %s: %s" %
                      (i,
                       device.get('deviceName',
                                  "SMS to %s" % device.get('phoneNumber'))))

            device = click.prompt('Which device would you like to use?',
                                  default=0)
            device = devices[device]
            if not api.send_verification_code(device):
                print("Failed to send verification code")
                sys.exit(1)

            code = click.prompt('Please enter validation code')
            if not api.validate_verification_code(device, code):
                print("Failed to verify verification code")
                sys.exit(1)

        return api
Exemplo n.º 3
0
    def __logIntoiCloud(self):
        global iCloudApi

        print("Logging into iCloud")
        iCloudApi = PyiCloudService(self.icloud_email, self.icloud_password)

        if iCloudApi.requires_2sa:
            print(
                "Two-factor authentication required. Your trusted devices are:"
            )

            devices = iCloudApi.trusted_devices
            for i, device in enumerate(devices):
                print("  %s: %s" %
                      (i,
                       device.get("deviceName",
                                  "SMS to %s" % device.get("phoneNumber"))))

            device = click.prompt("Which device would you like to use?",
                                  default=0)
            device = devices[device]
            if not iCloudApi.send_verification_code(device):
                print("Failed to send verification code")
                sys.exit(1)

            code = click.prompt("Please enter validation code")
            if not iCloudApi.validate_verification_code(device, code):
                print("Failed to verify verification code")
                sys.exit(1)
Exemplo n.º 4
0
def login():
    """ Get access to Icloud """

    api = PyiCloudService(icloud, passw)
    if api.requires_2sa:
        print("Two-step authentication required. Your trusted devices are:")

        devices = api.trusted_devices
        for i, device in enumerate(devices):
            print("  %s: %s" %
                  (i,
                   device.get('deviceName',
                              "SMS to %s" % device.get('phoneNumber'))))

        device = click.prompt('Which device would you like to use?', default=0)
        device = devices[device]
        if not api.send_verification_code(device):
            print("Failed to send verification code")
            sys.exit(1)

        code = click.prompt('Please enter validation code')
        if not api.validate_verification_code(device, code):
            print("Failed to verify verification code")
            sys.exit(1)

    print("Devices available:\n {}".format(api.devices))
    device = click.prompt('Which device would you like to select?', default=0)
    api.devices[device]

    return api
def authenticate(username, password):
    print("Signing in...")

    if password:
      icloud = PyiCloudService(username, password)
    else:
      icloud = PyiCloudService(username)

    if icloud.requires_2fa:
        print "Two-factor authentication required. Your trusted devices are:"

        devices = icloud.trusted_devices
        for i, device in enumerate(devices):
            print "  %s: %s" % (i, device.get('deviceName',
                "SMS to %s" % device.get('phoneNumber')))

        device = click.prompt('Which device would you like to use?', default=0)
        device = devices[device]
        if not icloud.send_verification_code(device):
            print "Failed to send verification code"
            sys.exit(1)

        code = click.prompt('Please enter validation code')
        if not icloud.validate_verification_code(device, code):
            print "Failed to verify verification code"
            sys.exit(1)

    return icloud
Exemplo n.º 6
0
def initIcloud(username, password):
    global icloud
    if not icloud:
        icloud = PyiCloudService(username, password)
        # two-factor authentication
        if icloud.requires_2fa:
            import click
            print "Two-factor authentication required. Your trusted devices are:"

            devices = icloud.trusted_devices
            for i, device in enumerate(devices):
                print "  %s: %s" % (i,
                                    device.get(
                                        'deviceName', "SMS to %s" %
                                        device.get('phoneNumber')))

            device = click.prompt('Which device would you like to use?',
                                  default=0)
            device = devices[device]
            if not icloud.send_verification_code(device):
                print "Failed to send verification code"
                return False

            code = click.prompt('Please enter validation code')
            if not icloud.validate_verification_code(device, code):
                print "Failed to verify verification code"
                return False
    return True
Exemplo n.º 7
0
def authenticate(username, password):
    """attempt to authenticate user using provided credentials"""

    icloud = PyiCloudService(username, password)

    if icloud.requires_2sa:
        print("Two-factor authentication required. Your trusted devices are:")

        devices = icloud.trusted_devices
        for i, device in enumerate(devices):
            print("  {0}: {1}".format(
                i,
                device.get('deviceName',
                           "SMS to %s" % device.get('phoneNumber'))))

        device = click.prompt('Which device would you like to use?', default=0)
        device = devices[device]
        if not icloud.send_verification_code(device):
            print("Failed to send verification code")
            sys.exit(1)

        code = click.prompt('Please enter validation code')
        if not icloud.validate_verification_code(device, code):
            print("Failed to verify verification code")
            sys.exit(1)

    return icloud
Exemplo n.º 8
0
def auth(username, password):

    print("認証を受けます。")
    sys.stdout.flush()
    api = PyiCloudService(username, password)
    print("認証が終わりました。")
    sys.stdout.flush()

    if api.requires_2sa:
        import click
        print("Two-step authentication required. Your trusted devices are:")

        devices = api.trusted_devices
        for i, device in enumerate(devices):
            print("  %s: %s" %
                  (i,
                   device.get('deviceName',
                              "SMS to %s" % device.get('phoneNumber'))))

        device = click.prompt('Which device would you like to use?', default=0)
        device = devices[device]
        if not api.send_verification_code(device):
            print("Failed to send verification code")
            sys.exit(1)

        code = click.prompt('Please enter validation code')
        if not api.validate_verification_code(device, code):
            print("Failed to verify verification code")
            sys.exit(1)

    return api
Exemplo n.º 9
0
def main():
    config = conf.Config()
    username = config.params.get('icloud', {}).get('username', None)
    password = config.params.get('icloud', {}).get('password', None)

    api = PyiCloudService(username, password)

    if api.requires_2fa:

        print ("Two-step authentisation required. Your trusted devices are:")

        devices = api.trusted_devices
        for i, device in enumerate(devices):
            print ("  %s: %s" % (i, device.get('deviceName',
                                               "SMS to %s" % device.get('phoneNumber'))))

        device = click.prompt('Which device would you like to use?', default=0)
        device = devices[device]
        if not api.send_verification_code(device):
            print ("Failed to send verification code")
            sys.exit(1)

        code = click.prompt('Please enter validation code')
        if not api.validate_verification_code(device, code):
            print ("Failed to verify verification code")
            sys.exit(1)
Exemplo n.º 10
0
def authenticate(username, password):
    if password:
        icloud = PyiCloudService(username, password)
    else:
        icloud = PyiCloudService(username)

    if icloud.requires_2fa:
        print "Two-factor authentication required. Your trusted devices are:"

        devices = icloud.trusted_devices
        for i, device in enumerate(devices):
            print "  %s: %s" % (i,
                                device.get(
                                    'deviceName',
                                    "SMS to %s" % device.get('phoneNumber')))

        device = click.prompt('Which device would you like to use?', default=0)
        device = devices[device]
        if not icloud.send_verification_code(device):
            print "Failed to send verification code"
            sys.exit(1)

        code = click.prompt('Please enter validation code')
        if not icloud.validate_verification_code(device, code):
            print "Failed to verify verification code"
            sys.exit(1)

        print "Great, you're all set up. Now re-run the script to print out filenames."
        sys.exit(1)

    return icloud
Exemplo n.º 11
0
def setup_icloud():
    #
    name = raw_input("Enter the name: ")
    username = raw_input("Username: "******"Password: "******"Two-factor authentication required. Your trusted devices are:")

            devices = api.trusted_devices
            for i, device in enumerate(devices):
                print "  %s: %s" % (i, device.get('deviceName',
                                                  "SMS to %s" % device.get('phoneNumber')))

            device = click.prompt('Which device would you like to use?', default=0)
            device = devices[device]
            if not api.send_verification_code(device):
                print("Failed to send verification code")
                sys.exit(1)

            code = click.prompt('Please enter validation code')
            if not api.validate_verification_code(device, code):
                print("Failed to verify verification code")
                sys.exit(1)
            #
            twofactor_choice = device
            twofactor_timestamp = datetime.datetime.now().strftime(_dateformat)
            #
        #
    except PyiCloudFailedLoginException:
        print("\n!! Username/password combination is incorrect - please try again !!")
        print("\n****************************************************************\n")
        return
    except:
        print("\n!! An error has ocurred - please try again !!")
        print("\n****************************************************************\n")
        return
    #
    new_acc = {}
    new_acc['account_type'] = 'icloud_account'
    new_acc['account_name'] = name
    new_acc['account_id'] = name.lower().replace(' ', '_').replace('\'', '')
    new_acc['details'] = {'username': username,
                          'password': password,
                          '2factor': {'2factor_required': api.requires_2fa,
                                      '2factor_choice': twofactor_choice,
                                      '2factor_timestamp': twofactor_timestamp}}
    new_acc['details_public'] = {}
    #
    return new_acc
Exemplo n.º 12
0
    def connect_to_icloud(
            self, config: Dict[str, Union[str, bool,
                                          None]]) -> PyiCloudService:
        self.logger.info("Connecting to iCloud…")
        if config["password"] == "":
            api = PyiCloudService(config["username"])
        else:
            api = PyiCloudService(config["username"], config["password"])

        if api.requires_2sa:
            print("Two-step authentication required.")

            if click.confirm(
                    "Have you received authentication request on any of your devices?"
            ):
                verification_function = lambda code: api.validate_2fa_code(code
                                                                           )
            else:
                print("Fallback to SMS verification.")
                print("Your trusted devices are:")
                devices = api.trusted_devices
                for i, device in enumerate(devices):
                    print("  {}: {}".format(
                        i,
                        device.get(
                            "deviceName",
                            "SMS to {}".format(device.get("phoneNumber")),
                        ),
                    ))
                device = click.prompt("Which device would you like to use?",
                                      default=0)
                device = devices[device]
                if not api.send_verification_code(device):
                    raise Exception("Failed to send verification code")
                verification_function = lambda code: api.validate_verification_code(
                    device, code)

            verified = False
            while not verified:
                code = click.prompt("Please enter validation code")
                verified = verification_function(code)
                self.logger.debug("Verification result: %s", verified)
                if verified:
                    print("Succeed")
                else:
                    print(
                        "Failed to verify verification code, retry (Ctrl-C to cancel)"
                    )

        return api
Exemplo n.º 13
0
def validate_icloud():
    api = PyiCloudService('*****@*****.**', 'REd#rED@1577?!?')
    print("Two-factor authentication required. Your trusted devices are:")
    devices = api.trusted_devices
    for i, device in enumerate(devices):
        print("  %s: %s" % (i,
                            device.get('deviceName', "SMS to %s" %
                                       device.get('phoneNumber'))))

    if not api.send_verification_code(device[0]):
        print("Failed to send verification code")
    code = click.prompt('Please enter validation code')
    if not api.validate_verification_code(device, code):
        print("Failed to verify verification code")
    print("iCloud Validated")
Exemplo n.º 14
0
def authenticate(username, password):
    """attempt to authenticate user using provided credentials"""

    api = PyiCloudService(username, password)

    if api.requires_2fa:
        print("Two-factor authentication required.")
        code = input(
            "Enter the code you received of one of your approved devices: ")
        result = api.validate_2fa_code(code)
        print("Code validation result: %s" % result)

        if not result:
            print("Failed to verify security code")
            sys.exit(1)

        if not api.is_trusted_session:
            print("Session is not trusted. Requesting trust...")
            result = api.trust_session()
            print("Session trust result %s" % result)

            if not result:
                print(
                    "Failed to request trust. You will likely be prompted for the code again in the coming weeks"
                )
    elif api.requires_2sa:
        import click
        print("Two-step authentication required. Your trusted devices are:")

        devices = api.trusted_devices
        for i, device in enumerate(devices):
            print("  %s: %s" %
                  (i,
                   device.get('deviceName',
                              "SMS to %s" % device.get('phoneNumber'))))

        device = click.prompt('Which device would you like to use?', default=0)
        device = devices[device]
        if not api.send_verification_code(device):
            print("Failed to send verification code")
            sys.exit(1)

        code = click.prompt('Please enter validation code')
        if not api.validate_verification_code(device, code):
            print("Failed to verify verification code")
            sys.exit(1)

    return api
Exemplo n.º 15
0
    def login(self, username, password):
        api = PyiCloudService(username, password)
        if api.requires_2fa:
            logging.info(
                f"ICloud with mail {username} required Two-factor authentication!"
            )
            result = api.validate_2fa_code(self.__get_2fa_code())

            if not result:
                logging.critical(
                    f"Failed to verify security code of ICloud-Account with mail {username}"
                )
                self.connected = False

            if not api.is_trusted_session:
                logging.info(
                    f"Session for mail, {username} is not trusted. Requesting trust..."
                )
                result = api.trust_session()
                print(f"Session trust for mail {username} result '{result}'")

                if not result:
                    logging.critical(
                        "Failed to request trust. You will likely be prompted for the code again in the coming weeks!"
                    )
                    self.connected = False
        elif api.requires_2sa:
            import click
            devices = api.trusted_devices
            for i, device in enumerate(devices):
                print("  %s: %s" %
                      (i,
                       device.get('deviceName',
                                  "SMS to %s" % device.get('phoneNumber'))))

            device = click.prompt('Which device would you like to use?',
                                  default=0)
            device = devices[device]
            if not api.send_verification_code(device):
                logging.critical("Failed to send verification code")
            code = click.prompt('Please enter validation code')

            if not api.validate_verification_code(device, code):
                logging.critical("Failed to verify verification code!")
                self.connected = False

        return api
def authenticate(username, password, \
    smtp_username, smtp_password, smtp_host, smtp_port, smtp_no_tls, \
    notification_email):
    if password:
        icloud = PyiCloudService(username, password)
    else:
        icloud = PyiCloudService(username)

    if icloud.requires_2sa:
        if smtp_username and smtp_password:
            # If running in the background, send a notification email.
            send_two_step_expired_notification(smtp_username, smtp_password, \
                smtp_host, smtp_port, smtp_no_tls, notification_email)
            exit()

        print("Two-factor authentication required. Your trusted devices are:")

        devices = icloud.trusted_devices
        for i, device in enumerate(devices):
            print("  %s: %s" %
                  (i,
                   device.get('deviceName',
                              "SMS to %s" % device.get('phoneNumber'))))

        device = click.prompt('Which device would you like to use?', default=0)
        device = devices[device]
        if not icloud.send_verification_code(device):
            print("Failed to send verification code")
            sys.exit(1)

        code = click.prompt('Please enter validation code')
        if not icloud.validate_verification_code(device, code):
            print("Failed to verify verification code")
            sys.exit(1)

        print(
            "Great, you're all set up. The script can now be run without user interaction."
        )
        print(
            "You can set up email notifications to receive a notification when two-step authentication expires."
        )
        print("Use --help to view information about SMTP options.")
        sys.exit(1)

    return icloud
Exemplo n.º 17
0
def authenticate_icloud(folder):
    username = click.prompt('Please enter your ICloud email').strip()
    password = click.prompt('Please enter your ICloud password').strip()
    tmp = os.path.join(tempfile.gettempdir(), 'photo-transfer-icloud')

    api = PyiCloudService(username, password, cookie_directory=folder)

    if api.requires_2sa:
        device = api.trusted_devices[0]
        phone = device.get('phoneNumber')
        if not api.send_verification_code(device):
            raise Exception(f'Failed to send verification code to {phone}')
        code = click.prompt(f'Please enter verification code sent to {phone}')
        if not api.validate_verification_code(device, code):
            raise Exception('Failed to verify verification code')

    with open(os.path.join(folder, 'icloud.json'), 'w') as file:
        file.write(f'{{"username":"******", "password":"******"}}')

    print('ICloud authentication succeeded')
Exemplo n.º 18
0
class ICloudCalendar:
    def __init__(self, username, password):
        self.connected = False
        self.verification_code_required = False
        self.api = PyiCloudService(username, password)

        if self.api.requires_2sa:
            self.verification_code_required = True
        else:
            self.connected = True

    def get_devices(self):
        return self.api.devices

    def send_code(self, device):
        if not self.connected:
            if not self.api.send_verification_code(device):
                raise Exception('Could not send verification code')
        else:
            raise Exception("Already connected")

    def validate_code(self, device, code):
        if not self.connected:
            if not self.api.validate_verification_code(device, code):
                raise Exception("Invalid verification code")
            else:
                self.verification_code_required = False
                self.connected = True
        else:
            raise Exception("Already connected")

    def get_events(self, start, end):
        if self.connected:
            return self.api.calendar.events(from_dt=start, to_dt=end)
        else:
            if self.verification_code_required:
                raise Exception("Not connected : Verification code is missing")
            else:
                raise Exception("Not connected")
Exemplo n.º 19
0
def authenticate(username, password, smtp_username, smtp_password, notification_email):
    if password:
      icloud = PyiCloudService(username, password)
    else:
      icloud = PyiCloudService(username)

    # Fixes bug in pyicloud - https://github.com/picklepete/pyicloud/pull/149
    # Rename to requires_2sa (with fallback) after this is merged.
    if hasattr(icloud, 'requires_2sa'):
        icloud.requires_2fa = icloud.requires_2sa

    if icloud.requires_2fa:
        if smtp_username and smtp_password:
            # If running in the background, send a notification email.
            send_two_step_expired_notification(smtp_username, smtp_password, notification_email)
            exit()

        print("Two-factor authentication required. Your trusted devices are:")

        devices = icloud.trusted_devices
        for i, device in enumerate(devices):
            print("  %s: %s" % (i, device.get('deviceName',
                "SMS to %s" % device.get('phoneNumber'))))

        device = click.prompt('Which device would you like to use?', default=0)
        device = devices[device]
        if not icloud.send_verification_code(device):
            print("Failed to send verification code")
            sys.exit(1)

        code = click.prompt('Please enter validation code')
        if not icloud.validate_verification_code(device, code):
            print("Failed to verify verification code")
            sys.exit(1)

        print("Great, you're all set up. Now re-run the script to print out filenames.")
        sys.exit(1)

    return icloud
Exemplo n.º 20
0
def main():
    iCloud_Account = os.getenv('ACCOUNT', '')
    DownloadFolder = '/Downloads'

    os.chdir(DownloadFolder)
    if len(iCloud_Account) == 0:
        iCloud_Account = input('Enter iCloud Account: ')
    password = getpass('Enter password of "%s": ' % iCloud_Account)
    api = PyiCloudService(iCloud_Account, password)
    if api.requires_2sa:
        if not api.send_verification_code(api.trusted_devices[0]):
            print("Failed to send verification code")
            sys.exit(1)
        code = click.prompt('Please enter validation code')
        if not api.validate_verification_code(api.trusted_devices[0], code):
            print("Failed to verify verification code")
            sys.exit(1)

    num = len(api.photos.albums)
    names = dict(zip(range(num), api.photos.albums.keys()))
    albums = dict(zip(range(num), api.photos.albums.values()))
    running = True
    while running:
        print("Found albums:")
        for i in range(num):
            print("%2d) %s" % (i, names[i]))
        option = click.prompt('Please choose an album to download: ')

        try:
            option = int(option)
        except:
            print("Not an integer.")
            sys.exit(1)

        if option < 0 or option >= num:
            running = False
            continue
        download_album(names[option], albums[option])
Exemplo n.º 21
0
def getLight():
	global gps
	apple_id = ""
	password = ""
	conn = sqlite3.connect('id_pass.db')
	cur = conn.cursor()
	cur.execute("SELECT * FROM pass")
	data = cur.fetchall()
	if len(data) == 0:
        	conn.close()
        	print("Error fetching data")
	elif len(data) > 0:
        	for item in data:
                	apple_id = str(item[0])
	                password = str(item[1])
		conn.close()
	api = PyiCloudService(apple_id, password)
	if api.requires_2fa:
		import click
		print("Two-factor authentication required. Your trusted devices are:")

		devices = api.trusted_devices
		for i, device in enumerate(devices):
			print("  %s: %s" % (i, device.get('deviceName',"SMS to %s" % device.get('phoneNumber'))))

		device = click.prompt('Which device would you like to use?', default=0)
		device = devices[device]
		if not api.send_verification_code(device):
			print("Failed to send verification code")
			sys.exit(1)

		code = click.prompt('Please enter validation code')
		if not api.validate_verification_code(device, code):
			print("Failed to verify verification code")
			sys.exit(1)
	tmp = json.loads(json.dumps(api.iphone.location()))
	tmp2 = str(tmp["longitude"]) + "," + str(tmp["latitude"])
	return {"gps":tmp2}
Exemplo n.º 22
0
def log():
    global api
    api = PyiCloudService('*****@*****.**', '')

    if api.requires_2sa:
        import click
        print("Two-step authentication required. Your trusted devices are:")

        devices = api.trusted_devices
        for i, device in enumerate(devices):
            print("  %s: %s" %
                  (i,
                   device.get('deviceName',
                              "SMS to %s" % device.get('phoneNumber'))))

        device = devices[0]
        if not api.send_verification_code(device):
            print("Failed to send verification code")
            sys.exit(1)

        code = input("code: ")
        if not api.validate_verification_code(device, code):
            print("Failed to verify verification code")
            sys.exit(1)
Exemplo n.º 23
0
class Icloud(DeviceScanner):
    """Representation of an iCloud account."""

    def __init__(self, hass, username, password, name, see, filter_devices):
        """Initialize an iCloud account."""
        self.hass = hass
        self.username = username
        self.password = password
        self.api = None
        self.accountname = name
        self.filter_devices = filter_devices
        self.devices = {}
        self.seen_devices = {}
        self._overridestates = {}
        self._intervals = {}
        self.see = see

        self._trusted_device = None
        self._verification_code = None

        self._attrs = {}
        self._attrs[ATTR_ACCOUNTNAME] = name

        self.reset_account_icloud()

        randomseconds = random.randint(10, 59)
        track_utc_time_change(
            self.hass, self.keep_alive, second=randomseconds)

    def reset_account_icloud(self):
        """Reset an iCloud account."""
        from pyicloud import PyiCloudService
        from pyicloud.exceptions import (
            PyiCloudFailedLoginException, PyiCloudNoDevicesException)

        icloud_dir = self.hass.config.path('icloud')
        if not os.path.exists(icloud_dir):
            os.makedirs(icloud_dir)

        try:
            self.api = PyiCloudService(
                self.username, self.password,
                cookie_directory=icloud_dir,
                verify=True)
        except PyiCloudFailedLoginException as error:
            self.api = None
            _LOGGER.error("Error logging into iCloud Service: %s", error)
            return

        try:
            self.devices = {}
            self._overridestates = {}
            self._intervals = {}
            for device in self.api.devices:
                status = device.status(DEVICESTATUSSET)
                devicename = slugify(status['name'].replace(' ', '', 99))
                if devicename not in self.devices:
                    self.devices[devicename] = device
                    self._intervals[devicename] = 1
                    self._overridestates[devicename] = None
        except PyiCloudNoDevicesException:
            _LOGGER.error('No iCloud Devices found!')

    def icloud_trusted_device_callback(self, callback_data):
        """Handle chosen trusted devices."""
        self._trusted_device = int(callback_data.get('trusted_device'))
        self._trusted_device = self.api.trusted_devices[self._trusted_device]

        if not self.api.send_verification_code(self._trusted_device):
            _LOGGER.error("Failed to send verification code")
            self._trusted_device = None
            return

        if self.accountname in _CONFIGURING:
            request_id = _CONFIGURING.pop(self.accountname)
            configurator = self.hass.components.configurator
            configurator.request_done(request_id)

        # Trigger the next step immediately
        self.icloud_need_verification_code()

    def icloud_need_trusted_device(self):
        """We need a trusted device."""
        configurator = self.hass.components.configurator
        if self.accountname in _CONFIGURING:
            return

        devicesstring = ''
        devices = self.api.trusted_devices
        for i, device in enumerate(devices):
            devicename = device.get(
                'deviceName', 'SMS to %s' % device.get('phoneNumber'))
            devicesstring += "{}: {};".format(i, devicename)

        _CONFIGURING[self.accountname] = configurator.request_config(
            'iCloud {}'.format(self.accountname),
            self.icloud_trusted_device_callback,
            description=(
                'Please choose your trusted device by entering'
                ' the index from this list: ' + devicesstring),
            entity_picture="/static/images/config_icloud.png",
            submit_caption='Confirm',
            fields=[{'id': 'trusted_device', 'name': 'Trusted Device'}]
        )

    def icloud_verification_callback(self, callback_data):
        """Handle the chosen trusted device."""
        from pyicloud.exceptions import PyiCloudException
        self._verification_code = callback_data.get('code')

        try:
            if not self.api.validate_verification_code(
                    self._trusted_device, self._verification_code):
                raise PyiCloudException('Unknown failure')
        except PyiCloudException as error:
            # Reset to the initial 2FA state to allow the user to retry
            _LOGGER.error("Failed to verify verification code: %s", error)
            self._trusted_device = None
            self._verification_code = None

            # Trigger the next step immediately
            self.icloud_need_trusted_device()

        if self.accountname in _CONFIGURING:
            request_id = _CONFIGURING.pop(self.accountname)
            configurator = self.hass.components.configurator
            configurator.request_done(request_id)

    def icloud_need_verification_code(self):
        """Return the verification code."""
        configurator = self.hass.components.configurator
        if self.accountname in _CONFIGURING:
            return

        _CONFIGURING[self.accountname] = configurator.request_config(
            'iCloud {}'.format(self.accountname),
            self.icloud_verification_callback,
            description=('Please enter the validation code:'),
            entity_picture="/static/images/config_icloud.png",
            submit_caption='Confirm',
            fields=[{'id': 'code', 'name': 'code'}]
        )

    def keep_alive(self, now):
        """Keep the API alive."""
        if self.api is None:
            self.reset_account_icloud()

        if self.api is None:
            return

        if self.api.requires_2fa:
            from pyicloud.exceptions import PyiCloudException
            try:
                if self._trusted_device is None:
                    self.icloud_need_trusted_device()
                    return

                if self._verification_code is None:
                    self.icloud_need_verification_code()
                    return

                self.api.authenticate()
                if self.api.requires_2fa:
                    raise Exception('Unknown failure')

                self._trusted_device = None
                self._verification_code = None
            except PyiCloudException as error:
                _LOGGER.error("Error setting up 2FA: %s", error)
        #else:
        #    self.api.authenticate()

        currentminutes = dt_util.now().hour * 60 + dt_util.now().minute
        try:
            for devicename in self.devices:
                interval = self._intervals.get(devicename, 1)
                if ((currentminutes % interval == 0) or
                        (interval > 10 and
                         currentminutes % interval in [2, 4])):
                    if (self.filter_devices in devicename): 
                        _LOGGER.debug("Updating device " + devicename)
                        self.api.authenticate()
                        self.update_device(devicename)
        except ValueError:
            _LOGGER.debug("iCloud API returned an error")

    def determine_interval(self, devicename, latitude, longitude, battery):
        """Calculate new interval."""
        distancefromhome = None
        zone_state = self.hass.states.get('zone.home')
        zone_state_lat = zone_state.attributes['latitude']
        zone_state_long = zone_state.attributes['longitude']
        distancefromhome = distance(
            latitude, longitude, zone_state_lat, zone_state_long)
        distancefromhome = round(distancefromhome / 1000, 1)

        currentzone = active_zone(self.hass, latitude, longitude)

        if ((currentzone is not None and
             currentzone == self._overridestates.get(devicename)) or
                (currentzone is None and
                 self._overridestates.get(devicename) == 'away')):
            return

        self._overridestates[devicename] = None

        if currentzone is not None:
            self._intervals[devicename] = 30
            return

        if distancefromhome is None:
            return
        if distancefromhome > 25:
            self._intervals[devicename] = round(distancefromhome / 2, 0)
        elif distancefromhome > 10:
            self._intervals[devicename] = 5
        else:
            self._intervals[devicename] = 1
        if battery is not None and battery <= 33 and distancefromhome > 3:
            self._intervals[devicename] = self._intervals[devicename] * 2

    def update_device(self, devicename):
        """Update the device_tracker entity."""
        from pyicloud.exceptions import PyiCloudNoDevicesException

        # An entity will not be created by see() when track=false in
        # 'known_devices.yaml', but we need to see() it at least once
        entity = self.hass.states.get(ENTITY_ID_FORMAT.format(devicename))
        if entity is None and devicename in self.seen_devices:
            return
        attrs = {}
        kwargs = {}

        if self.api is None:
            return

        if self.filter_devices not in devicename:
            return

        try:
            for device in self.api.devices:
                if str(device) != str(self.devices[devicename]):
                    continue

                status = device.status(DEVICESTATUSSET)
                dev_id = status['name'].replace(' ', '', 99)
                dev_id = slugify(dev_id)
                attrs[ATTR_DEVICESTATUS] = DEVICESTATUSCODES.get(
                    status['deviceStatus'], 'error')
                attrs[ATTR_LOWPOWERMODE] = status['lowPowerMode']
                attrs[ATTR_BATTERYSTATUS] = status['batteryStatus']
                attrs[ATTR_ACCOUNTNAME] = self.accountname
                status = device.status(DEVICESTATUSSET)
                battery = status.get('batteryLevel', 0) * 100
                location = status['location']
                if location:
                    self.determine_interval(
                        devicename, location['latitude'],
                        location['longitude'], battery)
                    interval = self._intervals.get(devicename, 1)
                    attrs[ATTR_INTERVAL] = interval
                    accuracy = location['horizontalAccuracy']
                    kwargs['dev_id'] = dev_id
                    kwargs['host_name'] = status['name']
                    kwargs['gps'] = (location['latitude'],
                                     location['longitude'])
                    kwargs['battery'] = battery
                    kwargs['gps_accuracy'] = accuracy
                    kwargs[ATTR_ATTRIBUTES] = attrs
                    self.see(**kwargs)
                    self.seen_devices[devicename] = True
        except PyiCloudNoDevicesException:
            _LOGGER.error("No iCloud Devices found")

    def lost_iphone(self, devicename):
        """Call the lost iPhone function if the device is found."""
        if self.api is None:
            return

        self.api.authenticate()

        for device in self.api.devices:
            if devicename is None or device == self.devices[devicename]:
                device.play_sound()

    def update_icloud(self, devicename=None):
        """Authenticate against iCloud and scan for devices."""
        from pyicloud.exceptions import PyiCloudNoDevicesException

        if self.api is None:
            return

        try:
            if devicename is not None:
                if devicename in self.devices:
                    self.devices[devicename].location()
                else:
                    _LOGGER.error("devicename %s unknown for account %s",
                                  devicename, self._attrs[ATTR_ACCOUNTNAME])
            else:
                for device in self.devices:
                    self.devices[device].location()
        except PyiCloudNoDevicesException:
            _LOGGER.error("No iCloud Devices found")

    def setinterval(self, interval=None, devicename=None):
        """Set the interval of the given devices."""
        devs = [devicename] if devicename else self.devices
        for device in devs:
            devid = '{}.{}'.format(DOMAIN, device)
            devicestate = self.hass.states.get(devid)
            if interval is not None:
                if devicestate is not None:
                    self._overridestates[device] = active_zone(
                        self.hass,
                        float(devicestate.attributes.get('latitude', 0)),
                        float(devicestate.attributes.get('longitude', 0)))
                    if self._overridestates[device] is None:
                        self._overridestates[device] = 'away'
                self._intervals[device] = interval
            else:
                self._overridestates[device] = None
            self.update_device(device)
Exemplo n.º 24
0
def main(args=None):
    """Main commandline entrypoint."""
    if args is None:
        args = sys.argv[1:]

    parser = argparse.ArgumentParser(
        description="Find My iPhone CommandLine Tool")

    parser.add_argument(
        "--username",
        action="store",
        dest="username",
        default="",
        help="Apple ID to Use",
    )
    parser.add_argument(
        "--password",
        action="store",
        dest="password",
        default="",
        help=("Apple ID Password to Use; if unspecified, password will be "
              "fetched from the system keyring."),
    )
    parser.add_argument(
        "-n",
        "--non-interactive",
        action="store_false",
        dest="interactive",
        default=True,
        help="Disable interactive prompts.",
    )
    parser.add_argument(
        "--delete-from-keyring",
        action="store_true",
        dest="delete_from_keyring",
        default=False,
        help="Delete stored password in system keyring for this username.",
    )
    parser.add_argument(
        "--list",
        action="store_true",
        dest="list",
        default=False,
        help="Short Listings for Device(s) associated with account",
    )
    parser.add_argument(
        "--llist",
        action="store_true",
        dest="longlist",
        default=False,
        help="Detailed Listings for Device(s) associated with account",
    )
    parser.add_argument(
        "--locate",
        action="store_true",
        dest="locate",
        default=False,
        help="Retrieve Location for the iDevice (non-exclusive).",
    )

    # Restrict actions to a specific devices UID / DID
    parser.add_argument(
        "--device",
        action="store",
        dest="device_id",
        default=False,
        help="Only effect this device",
    )

    # Trigger Sound Alert
    parser.add_argument(
        "--sound",
        action="store_true",
        dest="sound",
        default=False,
        help="Play a sound on the device",
    )

    # Trigger Message w/Sound Alert
    parser.add_argument(
        "--message",
        action="store",
        dest="message",
        default=False,
        help="Optional Text Message to display with a sound",
    )

    # Trigger Message (without Sound) Alert
    parser.add_argument(
        "--silentmessage",
        action="store",
        dest="silentmessage",
        default=False,
        help="Optional Text Message to display with no sounds",
    )

    # Lost Mode
    parser.add_argument(
        "--lostmode",
        action="store_true",
        dest="lostmode",
        default=False,
        help="Enable Lost mode for the device",
    )
    parser.add_argument(
        "--lostphone",
        action="store",
        dest="lost_phone",
        default=False,
        help="Phone Number allowed to call when lost mode is enabled",
    )
    parser.add_argument(
        "--lostpassword",
        action="store",
        dest="lost_password",
        default=False,
        help="Forcibly active this passcode on the idevice",
    )
    parser.add_argument(
        "--lostmessage",
        action="store",
        dest="lost_message",
        default="",
        help="Forcibly display this message when activating lost mode.",
    )

    # Output device data to an pickle file
    parser.add_argument(
        "--outputfile",
        action="store_true",
        dest="output_to_file",
        default="",
        help="Save device data to a file in the current directory.",
    )

    command_line = parser.parse_args(args)

    username = command_line.username
    password = command_line.password

    if username and command_line.delete_from_keyring:
        utils.delete_password_in_keyring(username)

    failure_count = 0
    while True:
        # Which password we use is determined by your username, so we
        # do need to check for this first and separately.
        if not username:
            parser.error("No username supplied")

        if not password:
            password = utils.get_password(username,
                                          interactive=command_line.interactive)

        if not password:
            parser.error("No password supplied")

        try:
            api = PyiCloudService(username.strip(), password.strip())
            if (not utils.password_exists_in_keyring(username)
                    and command_line.interactive
                    and confirm("Save password in keyring?")):
                utils.store_password_in_keyring(username, password)

            if api.requires_2sa:
                # fmt: off
                print("\nTwo-step authentication required.",
                      "\nYour trusted devices are:")
                # fmt: on

                devices = api.trusted_devices
                for i, device in enumerate(devices):
                    print("    %s: %s" % (
                        i,
                        device.get("deviceName",
                                   "SMS to %s" % device.get("phoneNumber")),
                    ))

                print("\nWhich device would you like to use?")
                device = int(input("(number) --> "))
                device = devices[device]
                if not api.send_verification_code(device):
                    print("Failed to send verification code")
                    sys.exit(1)

                print("\nPlease enter validation code")
                code = input("(string) --> ")
                if not api.validate_verification_code(device, code):
                    print("Failed to verify verification code")
                    sys.exit(1)

                print("")
            break
        except PyiCloudFailedLoginException:
            # If they have a stored password; we just used it and
            # it did not work; let's delete it if there is one.
            if utils.password_exists_in_keyring(username):
                utils.delete_password_in_keyring(username)

            message = "Bad username or password for {username}".format(
                username=username, )
            password = None

            failure_count += 1
            if failure_count >= 3:
                raise RuntimeError(message)

            print(message, file=sys.stderr)

    for dev in api.devices:
        if not command_line.device_id or (
                command_line.device_id.strip().lower()
                == dev.content["id"].strip().lower()):
            # List device(s)
            if command_line.locate:
                dev.location()

            if command_line.output_to_file:
                create_pickled_data(
                    dev,
                    filename=(dev.content["name"].strip().lower() +
                              ".fmip_snapshot"),
                )

            contents = dev.content
            if command_line.longlist:
                print("-" * 30)
                print(contents["name"])
                for key in contents:
                    print("%20s - %s" % (key, contents[key]))
            elif command_line.list:
                print("-" * 30)
                print("Name - %s" % contents["name"])
                print("Display Name  - %s" % contents["deviceDisplayName"])
                print("Location      - %s" % contents["location"])
                print("Battery Level - %s" % contents["batteryLevel"])
                print("Battery Status- %s" % contents["batteryStatus"])
                print("Device Class  - %s" % contents["deviceClass"])
                print("Device Model  - %s" % contents["deviceModel"])

            # Play a Sound on a device
            if command_line.sound:
                if command_line.device_id:
                    dev.play_sound()
                else:
                    raise RuntimeError("\n\n\t\t%s %s\n\n" % (
                        "Sounds can only be played on a singular device.",
                        DEVICE_ERROR,
                    ))

            # Display a Message on the device
            if command_line.message:
                if command_line.device_id:
                    dev.display_message(subject="A Message",
                                        message=command_line.message,
                                        sounds=True)
                else:
                    raise RuntimeError("%s %s" % (
                        "Messages can only be played on a singular device.",
                        DEVICE_ERROR,
                    ))

            # Display a Silent Message on the device
            if command_line.silentmessage:
                if command_line.device_id:
                    dev.display_message(
                        subject="A Silent Message",
                        message=command_line.silentmessage,
                        sounds=False,
                    )
                else:
                    raise RuntimeError("%s %s" % (
                        "Silent Messages can only be played "
                        "on a singular device.",
                        DEVICE_ERROR,
                    ))

            # Enable Lost mode
            if command_line.lostmode:
                if command_line.device_id:
                    dev.lost_device(
                        number=command_line.lost_phone.strip(),
                        text=command_line.lost_message.strip(),
                        newpasscode=command_line.lost_password.strip(),
                    )
                else:
                    raise RuntimeError("%s %s" % (
                        "Lost Mode can only be activated on a singular device.",
                        DEVICE_ERROR,
                    ))
    sys.exit(0)
Exemplo n.º 25
0
class ICloud():
    def __init__(self):
        #
        self._icloud = PyiCloudService(get_cfg_details_account_username(),
                                       get_cfg_details_account_password())
        #
        cache.cache['_2fa/2sv-complete'] = False

    # 2FA
    def check2fa(self):
        r = self._icloud.requires_2fa
        if r:
            return {'2fa': True}
        else:
            return {'2fa': False}

    def get_2fa_trusted_devices(self):
        if self._icloud.requires_2fa:
            devices = self._icloud.trusted_devices
            return {'2fa': True, 'devices': devices}
        else:
            return {'2fa': False, 'devices': []}

    def _get_2fa_trusted_device_default(self):
        devices = self.get_2fa_trusted_devices()
        if devices['2fa']:
            for d in devices['devices']:
                default_deviceType = get_cfg_details_2fa_deviceType()
                if d['deviceType'] == default_deviceType:
                    if default_deviceType == 'SMS':
                        return {'device': d}
            # if no default device found in list
            return {
                'device':
                False,
                'error':
                'Jarvis does not hold a default devices that matches those returned by iCloud.'
            }
        return {
            'device':
            False,
            'error':
            'iCloud has reported back that 2fa is not required for access to services.'
        }

    # note that 'device' must be in the correct dict structure
    def request_validation_code(self, device):
        if self._icloud.send_verification_code(device):
            return True
        else:
            return False

    def request_validation_code_default(self):
        #
        device = self._get_2fa_trusted_device_default()
        #
        if device['device']:
            return {'result': self.request_validation_code(device['device'])}
        else:
            return {'result': False, 'error': device['error']}

    # note that 'device' must be in the correct dict structure
    def validate_validation_code(self, device, code):
        if self._icloud.validate_verification_code(device, code):
            cache.cache['_2fa/2sv-complete'] = True
            return True
        else:
            return False

    def validate_validation_code_default(self, code):
        #
        device = self._get_2fa_trusted_device_default()
        #
        if device:
            return self.validate_validation_code(device, code)
        else:
            return False

    # Devices
    def get_devices(self):
        devices = self._icloud.devices
        return devices

    def get_iphone(self):
        devices = self._icloud.iphone
        return devices

    # Contacts
    def get_contacts(self):
        return self._icloud.contacts.all()

    # Calendar - events
    def get_events(self):
        return self._convert_icloud_events(self._icloud.calendar.events())

    def get_events_today(self):
        return self._get_events(date.today(), date.today())

    def get_events_tomorrow(self):
        return self._get_events(date.today() + timedelta(days=1),
                                date.today() + timedelta(days=1))

    def get_events_date(self, _date):
        return self._get_events(_date, _date)

    def get_events_daterange(self, dateFrom, dateTo):
        return self._get_events(dateFrom, dateTo)

    def _get_events(self, from_dt, to_dt):
        _events = self._icloud.calendar.events(from_dt, to_dt)
        _events = self._convert_icloud_events(_events)
        return _events

    # Calendar - birthdays
    def get_birthdays(self):
        contacts = self.get_contacts()
        birthdays = []
        for contact in contacts:
            if 'birthday' in contact.keys():
                #
                b = {'birthday': contact['birthday']}
                #
                if 'firstName' in contact.keys():
                    b['firstName'] = contact['firstName']
                #
                if 'lastName' in contact.keys():
                    b['lastName'] = contact['lastName']
                #
                birthdays.append(b)
        return birthdays

    @staticmethod
    def _get_calendar_details(_event):
        #
        calendar_name = get_cfg_details_calendar_name(_event['pGuid'])
        if not calendar_name:
            calendar_name = ''
        #
        calendar_colour = get_cfg_details_calendar_colour(_event['pGuid'])
        if not calendar_colour:
            calendar_colour = 'none'
        #
        return {'name': calendar_name, 'colour': calendar_colour}

    # guid = event id that is used in same event even across invitees
    # pGuid = calendar id unique to specific calendar and user
    def _convert_icloud_events(self, _events):
        #
        usedGuids = []
        tempGuids = {}
        for event in _events:
            if event['guid'] in tempGuids.keys():
                tempGuids[event['guid']].append(
                    self._get_calendar_details(event))
            else:
                tempGuids[event['guid']] = [self._get_calendar_details(event)]
        #
        new_events = []
        for event in _events:
            if not event['guid'] in usedGuids:
                # put event in structure for json
                new_e = self._convert_icloud_event(event)
                # find all calendars for this event and add to new_e
                if event['guid'] in tempGuids.keys():
                    new_e['calendars'] = tempGuids[event['guid']]
                #
                new_events.append(new_e)
                usedGuids.append(event['guid'])
        #
        return new_events

    def _convert_icloud_event(self, _event):
        #
        return {
            'title':
            _event['title'],
            'location':
            _event['location'],
            'start':
            self._convert_datetime_to_string(
                self._convert_icloud_to_datetime(_event['localStartDate'])),
            'end':
            self._convert_datetime_to_string(
                self._convert_icloud_to_datetime(_event['localEndDate'])),
            'duration':
            _event['duration'],
            'allDay':
            _event['allDay'],
            'calendars': []
        }

    # Following function will get events for the next 52 weeks and identify all unique calendars
    def get_icloud_calendars(self):
        events = self._icloud.calendar.events(
            date.today(),
            date.today() + timedelta(weeks=52))
        tempGuids = {}
        for event in events:
            if not event['pGuid'] in tempGuids.keys():
                tempGuids[event['pGuid']] = self._get_calendar_details(event)
        return tempGuids

    @staticmethod
    def _convert_icloud_to_datetime(_icloud_datetime):
        # datetime(year, month, day, hour=0, minute=0, second=0, microsecond=0)
        return datetime(_icloud_datetime[1], _icloud_datetime[2],
                        _icloud_datetime[3], _icloud_datetime[4],
                        _icloud_datetime[5])

    @staticmethod
    def _convert_datetime_to_string(_datetime):
        return _datetime.strftime('%Y-%m-%d %H-%M')
Exemplo n.º 26
0
class Icloud(DeviceScanner):
    """Representation of an iCloud account."""

    def __init__(self, hass, username, password, name, see):
        """Initialize an iCloud account."""
        self.hass = hass
        self.username = username
        self.password = password
        self.api = None
        self.accountname = name
        self.devices = {}
        self.seen_devices = {}
        self._overridestates = {}
        self._intervals = {}
        self.see = see

        self._trusted_device = None
        self._verification_code = None

        self._attrs = {}
        self._attrs[ATTR_ACCOUNTNAME] = name

        self.reset_account_icloud()

        randomseconds = random.randint(10, 59)
        track_utc_time_change(
            self.hass, self.keep_alive, second=randomseconds)

    def reset_account_icloud(self):
        """Reset an iCloud account."""
        from pyicloud import PyiCloudService
        from pyicloud.exceptions import (
            PyiCloudFailedLoginException, PyiCloudNoDevicesException)

        icloud_dir = self.hass.config.path('icloud')
        if not os.path.exists(icloud_dir):
            os.makedirs(icloud_dir)

        try:
            self.api = PyiCloudService(
                self.username, self.password,
                cookie_directory=icloud_dir,
                verify=True)
        except PyiCloudFailedLoginException as error:
            self.api = None
            _LOGGER.error("Error logging into iCloud Service: %s", error)
            return

        try:
            self.devices = {}
            self._overridestates = {}
            self._intervals = {}
            for device in self.api.devices:
                status = device.status(DEVICESTATUSSET)
                devicename = slugify(status['name'].replace(' ', '', 99))
                if devicename not in self.devices:
                    self.devices[devicename] = device
                    self._intervals[devicename] = 1
                    self._overridestates[devicename] = None
        except PyiCloudNoDevicesException:
            _LOGGER.error('No iCloud Devices found!')

    def icloud_trusted_device_callback(self, callback_data):
        """Handle chosen trusted devices."""
        self._trusted_device = int(callback_data.get('trusted_device'))
        self._trusted_device = self.api.trusted_devices[self._trusted_device]

        if not self.api.send_verification_code(self._trusted_device):
            _LOGGER.error("Failed to send verification code")
            self._trusted_device = None
            return

        if self.accountname in _CONFIGURING:
            request_id = _CONFIGURING.pop(self.accountname)
            configurator = self.hass.components.configurator
            configurator.request_done(request_id)

        # Trigger the next step immediately
        self.icloud_need_verification_code()

    def icloud_need_trusted_device(self):
        """We need a trusted device."""
        configurator = self.hass.components.configurator
        if self.accountname in _CONFIGURING:
            return

        devicesstring = ''
        devices = self.api.trusted_devices
        for i, device in enumerate(devices):
            devicename = device.get(
                'deviceName', 'SMS to %s' % device.get('phoneNumber'))
            devicesstring += "{}: {};".format(i, devicename)

        _CONFIGURING[self.accountname] = configurator.request_config(
            'iCloud {}'.format(self.accountname),
            self.icloud_trusted_device_callback,
            description=(
                'Please choose your trusted device by entering'
                ' the index from this list: ' + devicesstring),
            entity_picture="/static/images/config_icloud.png",
            submit_caption='Confirm',
            fields=[{'id': 'trusted_device', 'name': 'Trusted Device'}]
        )

    def icloud_verification_callback(self, callback_data):
        """Handle the chosen trusted device."""
        from pyicloud.exceptions import PyiCloudException
        self._verification_code = callback_data.get('code')

        try:
            if not self.api.validate_verification_code(
                    self._trusted_device, self._verification_code):
                raise PyiCloudException('Unknown failure')
        except PyiCloudException as error:
            # Reset to the initial 2FA state to allow the user to retry
            _LOGGER.error("Failed to verify verification code: %s", error)
            self._trusted_device = None
            self._verification_code = None

            # Trigger the next step immediately
            self.icloud_need_trusted_device()

        if self.accountname in _CONFIGURING:
            request_id = _CONFIGURING.pop(self.accountname)
            configurator = self.hass.components.configurator
            configurator.request_done(request_id)

    def icloud_need_verification_code(self):
        """Return the verification code."""
        configurator = self.hass.components.configurator
        if self.accountname in _CONFIGURING:
            return

        _CONFIGURING[self.accountname] = configurator.request_config(
            'iCloud {}'.format(self.accountname),
            self.icloud_verification_callback,
            description=('Please enter the validation code:'),
            entity_picture="/static/images/config_icloud.png",
            submit_caption='Confirm',
            fields=[{'id': 'code', 'name': 'code'}]
        )

    def keep_alive(self, now):
        """Keep the API alive."""
        if self.api is None:
            self.reset_account_icloud()

        if self.api is None:
            return

        if self.api.requires_2fa:
            from pyicloud.exceptions import PyiCloudException
            try:
                if self._trusted_device is None:
                    self.icloud_need_trusted_device()
                    return

                if self._verification_code is None:
                    self.icloud_need_verification_code()
                    return

                self.api.authenticate()
                if self.api.requires_2fa:
                    raise Exception('Unknown failure')

                self._trusted_device = None
                self._verification_code = None
            except PyiCloudException as error:
                _LOGGER.error("Error setting up 2FA: %s", error)
        else:
            self.api.authenticate()

        currentminutes = dt_util.now().hour * 60 + dt_util.now().minute
        try:
            for devicename in self.devices:
                interval = self._intervals.get(devicename, 1)
                if ((currentminutes % interval == 0) or
                        (interval > 10 and
                         currentminutes % interval in [2, 4])):
                    self.update_device(devicename)
        except ValueError:
            _LOGGER.debug("iCloud API returned an error")

    def determine_interval(self, devicename, latitude, longitude, battery):
        """Calculate new interval."""
        distancefromhome = None
        zone_state = self.hass.states.get('zone.home')
        zone_state_lat = zone_state.attributes['latitude']
        zone_state_long = zone_state.attributes['longitude']
        distancefromhome = distance(
            latitude, longitude, zone_state_lat, zone_state_long)
        distancefromhome = round(distancefromhome / 1000, 1)

        currentzone = active_zone(self.hass, latitude, longitude)

        if ((currentzone is not None and
             currentzone == self._overridestates.get(devicename)) or
                (currentzone is None and
                 self._overridestates.get(devicename) == 'away')):
            return

        self._overridestates[devicename] = None

        if currentzone is not None:
            self._intervals[devicename] = 30
            return

        if distancefromhome is None:
            return
        if distancefromhome > 25:
            self._intervals[devicename] = round(distancefromhome / 2, 0)
        elif distancefromhome > 10:
            self._intervals[devicename] = 5
        else:
            self._intervals[devicename] = 1
        if battery is not None and battery <= 33 and distancefromhome > 3:
            self._intervals[devicename] = self._intervals[devicename] * 2

    def update_device(self, devicename):
        """Update the device_tracker entity."""
        from pyicloud.exceptions import PyiCloudNoDevicesException

        # An entity will not be created by see() when track=false in
        # 'known_devices.yaml', but we need to see() it at least once
        entity = self.hass.states.get(ENTITY_ID_FORMAT.format(devicename))
        if entity is None and devicename in self.seen_devices:
            return
        attrs = {}
        kwargs = {}

        if self.api is None:
            return

        try:
            for device in self.api.devices:
                if str(device) != str(self.devices[devicename]):
                    continue

                status = device.status(DEVICESTATUSSET)
                dev_id = status['name'].replace(' ', '', 99)
                dev_id = slugify(dev_id)
                attrs[ATTR_DEVICESTATUS] = DEVICESTATUSCODES.get(
                    status['deviceStatus'], 'error')
                attrs[ATTR_LOWPOWERMODE] = status['lowPowerMode']
                attrs[ATTR_BATTERYSTATUS] = status['batteryStatus']
                attrs[ATTR_ACCOUNTNAME] = self.accountname
                status = device.status(DEVICESTATUSSET)
                battery = status.get('batteryLevel', 0) * 100
                location = status['location']
                if location:
                    self.determine_interval(
                        devicename, location['latitude'],
                        location['longitude'], battery)
                    interval = self._intervals.get(devicename, 1)
                    attrs[ATTR_INTERVAL] = interval
                    accuracy = location['horizontalAccuracy']
                    kwargs['dev_id'] = dev_id
                    kwargs['host_name'] = status['name']
                    kwargs['gps'] = (location['latitude'],
                                     location['longitude'])
                    kwargs['battery'] = battery
                    kwargs['gps_accuracy'] = accuracy
                    kwargs[ATTR_ATTRIBUTES] = attrs
                    self.see(**kwargs)
                    self.seen_devices[devicename] = True
        except PyiCloudNoDevicesException:
            _LOGGER.error("No iCloud Devices found")

    def lost_iphone(self, devicename):
        """Call the lost iPhone function if the device is found."""
        if self.api is None:
            return

        self.api.authenticate()

        for device in self.api.devices:
            if devicename is None or device == self.devices[devicename]:
                device.play_sound()

    def update_icloud(self, devicename=None):
        """Authenticate against iCloud and scan for devices."""
        from pyicloud.exceptions import PyiCloudNoDevicesException

        if self.api is None:
            return

        try:
            if devicename is not None:
                if devicename in self.devices:
                    self.devices[devicename].location()
                else:
                    _LOGGER.error("devicename %s unknown for account %s",
                                  devicename, self._attrs[ATTR_ACCOUNTNAME])
            else:
                for device in self.devices:
                    self.devices[device].location()
        except PyiCloudNoDevicesException:
            _LOGGER.error("No iCloud Devices found")

    def setinterval(self, interval=None, devicename=None):
        """Set the interval of the given devices."""
        devs = [devicename] if devicename else self.devices
        for device in devs:
            devid = '{}.{}'.format(DOMAIN, device)
            devicestate = self.hass.states.get(devid)
            if interval is not None:
                if devicestate is not None:
                    self._overridestates[device] = active_zone(
                        self.hass,
                        float(devicestate.attributes.get('latitude', 0)),
                        float(devicestate.attributes.get('longitude', 0)))
                    if self._overridestates[device] is None:
                        self._overridestates[device] = 'away'
                self._intervals[device] = interval
            else:
                self._overridestates[device] = None
            self.update_device(device)
Exemplo n.º 27
0
    print("Unable to read the apple credentials file '%s': %s" %
          (apple_creds_file, str(e)))
    sys.exit(1)

api = PyiCloudService(appleid, password, "~/.iCloudLocationFetcher")
if api.requires_2sa:
    import click
    print("Two-step authentication required. Your trusted devices are:")
    trusted_devices = api.trusted_devices
    for i, device in enumerate(trusted_devices):
        print("%s: %s" % (i,
                          device.get('deviceName',
                                     "SMS to %s" % device.get('phoneNumber'))))

    device = click.prompt('Which device would you like to use?', default=0)
    device = trusted_devices[device]
    if not api.send_verification_code(device):
        print("Failed to send verification code")
        sys.exit(1)
    code = click.prompt('Please enter validation code')
    if not api.validate_verification_code(dict(), code):
        print("Failed to verify verification code")
        sys.exit(1)

# provide some information on the devices
devices = api.devices
for i, device in enumerate(devices):
    print("%s: type: %s, name: %s, location enabled: %s" %
          (i, device.content['deviceDisplayName'], device.content['name'],
           str(device.content['locationEnabled'])))
Exemplo n.º 28
0
class Icloud(object):
    """Represent an icloud account in Home Assistant."""

    def __init__(self, hass, username, password, name, see):
        """Initialize an iCloud account."""
        self.hass = hass
        self.username = username
        self.password = password
        self.api = None
        self.accountname = name
        self.devices = {}
        self.seen_devices = {}
        self._overridestates = {}
        self._intervals = {}
        self.see = see

        self._trusted_device = None
        self._verification_code = None

        self._attrs = {}
        self._attrs[ATTR_ACCOUNTNAME] = name

        self.reset_account_icloud()

        randomseconds = random.randint(10, 59)
        track_utc_time_change(self.hass, self.keep_alive, second=randomseconds)

    def reset_account_icloud(self):
        """Reset an icloud account."""
        from pyicloud import PyiCloudService
        from pyicloud.exceptions import PyiCloudFailedLoginException, PyiCloudNoDevicesException

        icloud_dir = self.hass.config.path("icloud")
        if not os.path.exists(icloud_dir):
            os.makedirs(icloud_dir)

        try:
            self.api = PyiCloudService(self.username, self.password, cookie_directory=icloud_dir, verify=True)
        except PyiCloudFailedLoginException as error:
            self.api = None
            _LOGGER.error("Error logging into iCloud Service: %s", error)
            return

        try:
            self.devices = {}
            self._overridestates = {}
            self._intervals = {}
            for device in self.api.devices:
                status = device.status(DEVICESTATUSSET)
                devicename = slugify(status["name"].replace(" ", "", 99))
                if devicename not in self.devices:
                    self.devices[devicename] = device
                    self._intervals[devicename] = 1
                    self._overridestates[devicename] = None
        except PyiCloudNoDevicesException:
            _LOGGER.error("No iCloud Devices found!")

    def icloud_trusted_device_callback(self, callback_data):
        """The trusted device is chosen."""
        self._trusted_device = int(callback_data.get("0", "0"))
        self._trusted_device = self.api.trusted_devices[self._trusted_device]
        if self.accountname in _CONFIGURING:
            request_id = _CONFIGURING.pop(self.accountname)
            configurator = get_component("configurator")
            configurator.request_done(request_id)

    def icloud_need_trusted_device(self):
        """We need a trusted device."""
        configurator = get_component("configurator")
        if self.accountname in _CONFIGURING:
            return

        devicesstring = ""
        devices = self.api.trusted_devices
        for i, device in enumerate(devices):
            devicesstring += "{}: {};".format(i, device.get("deviceName"))

        _CONFIGURING[self.accountname] = configurator.request_config(
            self.hass,
            "iCloud {}".format(self.accountname),
            self.icloud_trusted_device_callback,
            description=("Please choose your trusted device by entering" " the index from this list: " + devicesstring),
            entity_picture="/static/images/config_icloud.png",
            submit_caption="Confirm",
            fields=[{"id": "0"}],
        )

    def icloud_verification_callback(self, callback_data):
        """The trusted device is chosen."""
        self._verification_code = callback_data.get("0")
        if self.accountname in _CONFIGURING:
            request_id = _CONFIGURING.pop(self.accountname)
            configurator = get_component("configurator")
            configurator.request_done(request_id)

    def icloud_need_verification_code(self):
        """We need a verification code."""
        configurator = get_component("configurator")
        if self.accountname in _CONFIGURING:
            return

        if self.api.send_verification_code(self._trusted_device):
            self._verification_code = "waiting"

        _CONFIGURING[self.accountname] = configurator.request_config(
            self.hass,
            "iCloud {}".format(self.accountname),
            self.icloud_verification_callback,
            description=("Please enter the validation code:"),
            entity_picture="/static/images/config_icloud.png",
            submit_caption="Confirm",
            fields=[{"code": "0"}],
        )

    def keep_alive(self, now):
        """Keep the api alive."""
        from pyicloud.exceptions import PyiCloud2FARequiredError

        if self.api is None:
            self.reset_account_icloud()

        if self.api is None:
            return

        if self.api.requires_2fa:
            try:
                self.api.authenticate()
            except PyiCloud2FARequiredError:
                if self._trusted_device is None:
                    self.icloud_need_trusted_device()
                    return

                if self._verification_code is None:
                    self.icloud_need_verification_code()
                    return

                if self._verification_code == "waiting":
                    return

                if self.api.validate_verification_code(self._trusted_device, self._verification_code):
                    self._verification_code = None
        else:
            self.api.authenticate()

        currentminutes = dt_util.now().hour * 60 + dt_util.now().minute
        for devicename in self.devices:
            interval = self._intervals.get(devicename, 1)
            if (currentminutes % interval == 0) or (interval > 10 and currentminutes % interval in [2, 4]):
                self.update_device(devicename)

    def determine_interval(self, devicename, latitude, longitude, battery):
        """Calculate new interval."""
        distancefromhome = None
        zone_state = self.hass.states.get("zone.home")
        zone_state_lat = zone_state.attributes["latitude"]
        zone_state_long = zone_state.attributes["longitude"]
        distancefromhome = distance(latitude, longitude, zone_state_lat, zone_state_long)
        distancefromhome = round(distancefromhome / 1000, 1)

        currentzone = active_zone(self.hass, latitude, longitude)

        if (currentzone is not None and currentzone == self._overridestates.get(devicename)) or (
            currentzone is None and self._overridestates.get(devicename) == "away"
        ):
            return

        self._overridestates[devicename] = None

        if currentzone is not None:
            self._intervals[devicename] = 30
            return

        if distancefromhome is None:
            return
        if distancefromhome > 25:
            self._intervals[devicename] = round(distancefromhome / 2, 0)
        elif distancefromhome > 10:
            self._intervals[devicename] = 5
        else:
            self._intervals[devicename] = 1
        if battery is not None and battery <= 33 and distancefromhome > 3:
            self._intervals[devicename] = self._intervals[devicename] * 2

    def update_device(self, devicename):
        """Update the device_tracker entity."""
        from pyicloud.exceptions import PyiCloudNoDevicesException

        # An entity will not be created by see() when track=false in
        # 'known_devices.yaml', but we need to see() it at least once
        entity = self.hass.states.get(ENTITY_ID_FORMAT.format(devicename))
        if entity is None and devicename in self.seen_devices:
            return
        attrs = {}
        kwargs = {}

        if self.api is None:
            return

        try:
            for device in self.api.devices:
                if str(device) != str(self.devices[devicename]):
                    continue

                status = device.status(DEVICESTATUSSET)
                dev_id = status["name"].replace(" ", "", 99)
                dev_id = slugify(dev_id)
                attrs[ATTR_DEVICESTATUS] = DEVICESTATUSCODES.get(status["deviceStatus"], "error")
                attrs[ATTR_LOWPOWERMODE] = status["lowPowerMode"]
                attrs[ATTR_BATTERYSTATUS] = status["batteryStatus"]
                attrs[ATTR_ACCOUNTNAME] = self.accountname
                status = device.status(DEVICESTATUSSET)
                battery = status.get("batteryLevel", 0) * 100
                location = status["location"]
                if location:
                    self.determine_interval(devicename, location["latitude"], location["longitude"], battery)
                    interval = self._intervals.get(devicename, 1)
                    attrs[ATTR_INTERVAL] = interval
                    accuracy = location["horizontalAccuracy"]
                    kwargs["dev_id"] = dev_id
                    kwargs["host_name"] = status["name"]
                    kwargs["gps"] = (location["latitude"], location["longitude"])
                    kwargs["battery"] = battery
                    kwargs["gps_accuracy"] = accuracy
                    kwargs[ATTR_ATTRIBUTES] = attrs
                    self.see(**kwargs)
                    self.seen_devices[devicename] = True
        except PyiCloudNoDevicesException:
            _LOGGER.error("No iCloud Devices found!")

    def lost_iphone(self, devicename):
        """Call the lost iphone function if the device is found."""
        if self.api is None:
            return

        self.api.authenticate()

        for device in self.api.devices:
            if devicename is None or device == self.devices[devicename]:
                device.play_sound()

    def update_icloud(self, devicename=None):
        """Authenticate against iCloud and scan for devices."""
        from pyicloud.exceptions import PyiCloudNoDevicesException

        if self.api is None:
            return

        try:
            if devicename is not None:
                if devicename in self.devices:
                    self.devices[devicename].update_icloud()
                else:
                    _LOGGER.error("devicename %s unknown for account %s", devicename, self._attrs[ATTR_ACCOUNTNAME])
            else:
                for device in self.devices:
                    self.devices[device].update_icloud()
        except PyiCloudNoDevicesException:
            _LOGGER.error("No iCloud Devices found!")

    def setinterval(self, interval=None, devicename=None):
        """Set the interval of the given devices."""
        devs = [devicename] if devicename else self.devices
        for device in devs:
            devid = DOMAIN + "." + device
            devicestate = self.hass.states.get(devid)
            if interval is not None:
                if devicestate is not None:
                    self._overridestates[device] = active_zone(
                        self.hass,
                        float(devicestate.attributes.get("latitude", 0)),
                        float(devicestate.attributes.get("longitude", 0)),
                    )
                    if self._overridestates[device] is None:
                        self._overridestates[device] = "away"
                self._intervals[device] = interval
            else:
                self._overridestates[device] = None
            self.update_device(device)
Exemplo n.º 29
0
class iCloud:
    def __init__(self):
        creds = self.__load_creds(os.getcwd() + "/Secrets.txt")
        self.api = PyiCloudService(creds[0], creds[1])
        self.__two_factor_routine()
        self.phone = self.Phone()
        self.update_phone()

        self.lats, self.longs = self.__load_location()

    def __load_location(self):
        with open("location.txt", "r") as f:
            temp = f.readlines()
        out = []
        for i in temp:
            i = i.strip()
            i = i.split(",")
            out.append([float(j) for j in i])
        return out[0], out[1]

    def update_phone(self):
        _phone = self.api.devices[1]
        status = _phone.status()
        self.phone.update(_phone.content, status)

    def __load_creds(self, path):
        with open(path, "r") as f:
            creds = f.readlines()
        return [i.strip() for i in creds]

    # Not my code. This was ripped from pycloud docs.
    def __two_factor_routine(self):
        if self.api.requires_2fa:
            print("Two-factor authentication required.")
            code = input(
                "Enter the code you received of one of your approved devices: "
            )
            result = self.api.validate_2fa_code(code)
            print("Code validation result: %s" % result)

            if not result:
                print("Failed to verify security code")
                sys.exit(1)

            if not self.api.is_trusted_session:
                print("Session is not trusted. Requesting trust...")
                result = self.api.trust_session()
                print("Session trust result %s" % result)

                if not result:
                    print(
                        "Failed to request trust. You will likely be prompted for the code again in the coming weeks"
                    )
        elif self.api.requires_2sa:
            import click
            print(
                "Two-step authentication required. Your trusted devices are:")

            devices = self.api.trusted_devices
            for i, device in enumerate(devices):
                print("  %s: %s" %
                      (i,
                       device.get('deviceName',
                                  "SMS to %s" % device.get('phoneNumber'))))

            device = click.prompt('Which device would you like to use?',
                                  default=0)
            device = devices[device]
            if not self.api.send_verification_code(device):
                print("Failed to send verification code")
                sys.exit(1)

            code = click.prompt('Please enter validation code')
            if not self.api.validate_verification_code(device, code):
                print("Failed to verify verification code")
                sys.exit(1)

    def is_charging(self):
        first = self.api.devices[1].status()["batteryLevel"]
        count = 0

        while True:
            time.sleep(20)
            second = self.api.devices[1].status()["batteryLevel"]
            print("First {} --> Second {}".format(first, second))
            if second != first:
                break
            count += 1
        if second - first > 0.0:
            return True
        else:
            return False

    def is_home(self):
        lat_fence = self.lats
        long_fence = self.longs

        lat_check = self.phone.location[0] > lat_fence[
            0] and self.phone.location[0] < lat_fence[1]
        long_check = self.phone.location[1] < long_fence[
            0] and self.phone.location[1] > long_fence[1]
        return lat_check and long_check

    class Phone:
        def __init__(self):
            self.battery = 0.0
            self.location = []
            self.id = ""
            self.timestamp = None

        def update(self, content, status):
            self.timestamp = datetime.datetime.now()
            self.battery = status["batteryLevel"]
            self.id = content["id"]
            lat = content["location"]["latitude"]
            long = content["location"]["longitude"]
            self.location = [lat, long]
Exemplo n.º 30
0
class Icloud(DeviceScanner):
    """Representation of an iCloud account."""
    def __init__(self, hass, username, password, name, max_interval,
                 gps_accuracy_threshold, see):
        """Initialize an iCloud account."""
        self.hass = hass
        self.username = username
        self.password = password
        self.api = None
        self.accountname = name
        self.devices = {}
        self.seen_devices = {}
        self._overridestates = {}
        self._intervals = {}
        self._max_interval = max_interval
        self._gps_accuracy_threshold = gps_accuracy_threshold
        self.see = see

        self._trusted_device = None
        self._verification_code = None

        self._attrs = {}
        self._attrs[ATTR_ACCOUNTNAME] = name

        self.reset_account_icloud()

        randomseconds = random.randint(10, 59)
        track_utc_time_change(self.hass, self.keep_alive, second=randomseconds)

    def reset_account_icloud(self):
        """Reset an iCloud account."""
        from pyicloud import PyiCloudService
        from pyicloud.exceptions import (
            PyiCloudFailedLoginException,
            PyiCloudNoDevicesException,
        )

        icloud_dir = self.hass.config.path("icloud")
        if not os.path.exists(icloud_dir):
            os.makedirs(icloud_dir)

        try:
            self.api = PyiCloudService(self.username,
                                       self.password,
                                       cookie_directory=icloud_dir,
                                       verify=True)
        except PyiCloudFailedLoginException as error:
            self.api = None
            _LOGGER.error("Error logging into iCloud Service: %s", error)
            return

        try:
            self.devices = {}
            self._overridestates = {}
            self._intervals = {}
            for device in self.api.devices:
                status = device.status(DEVICESTATUSSET)
                _LOGGER.debug("Device Status is %s", status)
                devicename = slugify(status["name"].replace(" ", "", 99))
                _LOGGER.info("Adding icloud device: %s", devicename)
                if devicename in self.devices:
                    _LOGGER.error("Multiple devices with name: %s", devicename)
                    continue
                self.devices[devicename] = device
                self._intervals[devicename] = 1
                self._overridestates[devicename] = None
        except PyiCloudNoDevicesException:
            _LOGGER.error("No iCloud Devices found!")

    def icloud_trusted_device_callback(self, callback_data):
        """Handle chosen trusted devices."""
        self._trusted_device = int(callback_data.get("trusted_device"))
        self._trusted_device = self.api.trusted_devices[self._trusted_device]

        if not self.api.send_verification_code(self._trusted_device):
            _LOGGER.error("Failed to send verification code")
            self._trusted_device = None
            return

        if self.accountname in _CONFIGURING:
            request_id = _CONFIGURING.pop(self.accountname)
            configurator = self.hass.components.configurator
            configurator.request_done(request_id)

        # Trigger the next step immediately
        self.icloud_need_verification_code()

    def icloud_need_trusted_device(self):
        """We need a trusted device."""
        configurator = self.hass.components.configurator
        if self.accountname in _CONFIGURING:
            return

        devicesstring = ""
        devices = self.api.trusted_devices
        for i, device in enumerate(devices):
            devicename = device.get("deviceName",
                                    "SMS to %s" % device.get("phoneNumber"))
            devicesstring += "{}: {};".format(i, devicename)

        _CONFIGURING[self.accountname] = configurator.request_config(
            "iCloud {}".format(self.accountname),
            self.icloud_trusted_device_callback,
            description=("Please choose your trusted device by entering"
                         " the index from this list: " + devicesstring),
            entity_picture="/static/images/config_icloud.png",
            submit_caption="Confirm",
            fields=[{
                "id": "trusted_device",
                "name": "Trusted Device"
            }],
        )

    def icloud_verification_callback(self, callback_data):
        """Handle the chosen trusted device."""
        from pyicloud.exceptions import PyiCloudException

        self._verification_code = callback_data.get("code")

        try:
            if not self.api.validate_verification_code(
                    self._trusted_device, self._verification_code):
                raise PyiCloudException("Unknown failure")
        except PyiCloudException as error:
            # Reset to the initial 2FA state to allow the user to retry
            _LOGGER.error("Failed to verify verification code: %s", error)
            self._trusted_device = None
            self._verification_code = None

            # Trigger the next step immediately
            self.icloud_need_trusted_device()

        if self.accountname in _CONFIGURING:
            request_id = _CONFIGURING.pop(self.accountname)
            configurator = self.hass.components.configurator
            configurator.request_done(request_id)

    def icloud_need_verification_code(self):
        """Return the verification code."""
        configurator = self.hass.components.configurator
        if self.accountname in _CONFIGURING:
            return

        _CONFIGURING[self.accountname] = configurator.request_config(
            "iCloud {}".format(self.accountname),
            self.icloud_verification_callback,
            description=("Please enter the validation code:"),
            entity_picture="/static/images/config_icloud.png",
            submit_caption="Confirm",
            fields=[{
                "id": "code",
                "name": "code"
            }],
        )

    def keep_alive(self, now):
        """Keep the API alive."""
        if self.api is None:
            self.reset_account_icloud()

        if self.api is None:
            return

        if self.api.requires_2fa:
            from pyicloud.exceptions import PyiCloudException

            try:
                if self._trusted_device is None:
                    self.icloud_need_trusted_device()
                    return

                if self._verification_code is None:
                    self.icloud_need_verification_code()
                    return

                self.api.authenticate()
                if self.api.requires_2fa:
                    raise Exception("Unknown failure")

                self._trusted_device = None
                self._verification_code = None
            except PyiCloudException as error:
                _LOGGER.error("Error setting up 2FA: %s", error)
        else:
            self.api.authenticate()

        currentminutes = dt_util.now().hour * 60 + dt_util.now().minute
        try:
            for devicename in self.devices:
                interval = self._intervals.get(devicename, 1)
                if (currentminutes % interval
                        == 0) or (interval > 10
                                  and currentminutes % interval in [2, 4]):
                    self.update_device(devicename)
        except ValueError:
            _LOGGER.debug("iCloud API returned an error")

    def determine_interval(self, devicename, latitude, longitude, battery):
        """Calculate new interval."""
        currentzone = run_callback_threadsafe(self.hass.loop,
                                              async_active_zone, self.hass,
                                              latitude, longitude).result()

        if (currentzone is not None
                and currentzone == self._overridestates.get(devicename)) or (
                    currentzone is None
                    and self._overridestates.get(devicename) == "away"):
            return

        zones = (self.hass.states.get(entity_id)
                 for entity_id in sorted(self.hass.states.entity_ids("zone")))

        distances = []
        for zone_state in zones:
            zone_state_lat = zone_state.attributes["latitude"]
            zone_state_long = zone_state.attributes["longitude"]
            zone_distance = distance(latitude, longitude, zone_state_lat,
                                     zone_state_long)
            distances.append(round(zone_distance / 1000, 1))

        if distances:
            mindistance = min(distances)
        else:
            mindistance = None

        self._overridestates[devicename] = None

        if currentzone is not None:
            self._intervals[devicename] = self._max_interval
            return

        if mindistance is None:
            return

        # Calculate out how long it would take for the device to drive to the
        # nearest zone at 120 km/h:
        interval = round(mindistance / 2, 0)

        # Never poll more than once per minute
        interval = max(interval, 1)

        if interval > 180:
            # Three hour drive?  This is far enough that they might be flying
            interval = 30

        if battery is not None and battery <= 33 and mindistance > 3:
            # Low battery - let's check half as often
            interval = interval * 2

        self._intervals[devicename] = interval

    def update_device(self, devicename):
        """Update the device_tracker entity."""
        from pyicloud.exceptions import PyiCloudNoDevicesException

        # An entity will not be created by see() when track=false in
        # 'known_devices.yaml', but we need to see() it at least once
        entity = self.hass.states.get(ENTITY_ID_FORMAT.format(devicename))
        if entity is None and devicename in self.seen_devices:
            return
        attrs = {}
        kwargs = {}

        if self.api is None:
            return

        try:
            for device in self.api.devices:
                if str(device) != str(self.devices[devicename]):
                    continue

                status = device.status(DEVICESTATUSSET)
                _LOGGER.debug("Device Status is %s", status)
                dev_id = status["name"].replace(" ", "", 99)
                dev_id = slugify(dev_id)
                attrs[ATTR_DEVICESTATUS] = DEVICESTATUSCODES.get(
                    status["deviceStatus"], "error")
                attrs[ATTR_LOWPOWERMODE] = status["lowPowerMode"]
                attrs[ATTR_BATTERYSTATUS] = status["batteryStatus"]
                attrs[ATTR_ACCOUNTNAME] = self.accountname
                status = device.status(DEVICESTATUSSET)
                battery = status.get("batteryLevel", 0) * 100
                location = status["location"]
                if location and location["horizontalAccuracy"]:
                    horizontal_accuracy = int(location["horizontalAccuracy"])
                    if horizontal_accuracy < self._gps_accuracy_threshold:
                        self.determine_interval(
                            devicename,
                            location["latitude"],
                            location["longitude"],
                            battery,
                        )
                        interval = self._intervals.get(devicename, 1)
                        attrs[ATTR_INTERVAL] = interval
                        accuracy = location["horizontalAccuracy"]
                        kwargs["dev_id"] = dev_id
                        kwargs["host_name"] = status["name"]
                        kwargs["gps"] = (location["latitude"],
                                         location["longitude"])
                        kwargs["battery"] = battery
                        kwargs["gps_accuracy"] = accuracy
                        kwargs[ATTR_ATTRIBUTES] = attrs
                        self.see(**kwargs)
                        self.seen_devices[devicename] = True
        except PyiCloudNoDevicesException:
            _LOGGER.error("No iCloud Devices found")

    def lost_iphone(self, devicename):
        """Call the lost iPhone function if the device is found."""
        if self.api is None:
            return

        self.api.authenticate()
        for device in self.api.devices:
            if str(device) == str(self.devices[devicename]):
                _LOGGER.info("Playing Lost iPhone sound for %s", devicename)
                device.play_sound()

    def update_icloud(self, devicename=None):
        """Request device information from iCloud and update device_tracker."""
        from pyicloud.exceptions import PyiCloudNoDevicesException

        if self.api is None:
            return

        try:
            if devicename is not None:
                if devicename in self.devices:
                    self.update_device(devicename)
                else:
                    _LOGGER.error(
                        "devicename %s unknown for account %s",
                        devicename,
                        self._attrs[ATTR_ACCOUNTNAME],
                    )
            else:
                for device in self.devices:
                    self.update_device(device)
        except PyiCloudNoDevicesException:
            _LOGGER.error("No iCloud Devices found")

    def setinterval(self, interval=None, devicename=None):
        """Set the interval of the given devices."""
        devs = [devicename] if devicename else self.devices
        for device in devs:
            devid = "{}.{}".format(DOMAIN, device)
            devicestate = self.hass.states.get(devid)
            if interval is not None:
                if devicestate is not None:
                    self._overridestates[device] = run_callback_threadsafe(
                        self.hass.loop,
                        async_active_zone,
                        self.hass,
                        float(devicestate.attributes.get("latitude", 0)),
                        float(devicestate.attributes.get("longitude", 0)),
                    ).result()
                    if self._overridestates[device] is None:
                        self._overridestates[device] = "away"
                self._intervals[device] = interval
            else:
                self._overridestates[device] = None
            self.update_device(device)
Exemplo n.º 31
0
        filename=DEFAULT_LOGFILE, level=args.verbose and logging.DEBUG or logging.INFO,
        format='%(asctime)s %(message)s')

    gConfigurationiCloud, _, _ = configurationManager(args.config)
    api = PyiCloudService(gConfigurationiCloud['username'], gConfigurationiCloud['password'])

    if api.requires_2fa:
        print "Two-factor authentication required. Your trusted devices are:"

        devices = api.trusted_devices
        for i, device in enumerate(devices):
            print "  %s: %s" % (i, device.get('deviceName',
                "SMS to %s" % device.get('phoneNumber')))

        device = click.prompt('Which device would you like to use?', default=0)
        device = devices[device]
        if not api.send_verification_code(device):
            print "Failed to send verification code"
            sys.exit(1)

        code = click.prompt('Please enter validation code')
        if not api.validate_verification_code(device, code):
            print "Failed to verify verification code"
            sys.exit(1)
    else:
        print "2 Factor authentication not necessary"
    print "now run iLocator .. "



Exemplo n.º 32
0
def handle(text, mic, profile):
    """
        Makes your iPhone ring

        Arguments:
        text -- user-input, typically transcribed speech
        mic -- used to interact with the user (for both input and output)
        profile -- contains information related to the user (e.g., phone
                   number)
    """
    try:
        api = PyiCloudService(ICLOUD_USERNAME, ICLOUD_PASSWORD)

        #----- 2 FACTOR
        if api.requires_2fa:
            mic.say("I'm sorry Toby, I need you to validate iCloud for me.")
            import click
            print "Two-factor authentication required. Your trusted devices are:"

            devices = api.trusted_devices
            for i, device in enumerate(devices):
                print "  %s: %s" % (i,
                                    device.get(
                                        'deviceName', "SMS to %s" %
                                        device.get('phoneNumber')))

            device = click.prompt('Which device would you like to use?',
                                  default=0)
            device = devices[device]
            api.send_verification_code(device)
            #if not api.send_verification_code(device):
            #    print "Failed to send verification code"
            #sys.exit(1)

            code = click.prompt('Please enter validation code')
            if not api.validate_verification_code(device, code):
                mic.say("Failed to verify verification code")
                sys.exit(1)

            #-------END 2 FACTOR

    except PyiCloudFailedLoginException:
        mic.say("Invalid Username & Password")
        return

    # All Devices
    devices = api.devices

    # Just the iPhones
    iphones = []

    # The one to ring
    phone_to_ring = None

    for device in devices:
        current = device.status()
        if "iPhone" in current['deviceDisplayName']:
            iphones.append(device)

    # No iphones
    if len(iphones) == 0:
        mic.say("No IPhones Found on your account")
        return

    # Many iphones
    elif len(iphones) > 1:
        #mic.say("There are multiple iphones on your account.")
        count = 0
        for phone in iphones:
            #WILL ALWAYS SELECT THE SECOND IPHONE AS THAT IS MINE
            count += 1
            if count != 2:
                continue  #my iphone is second in list, so i removed the first
            #print(phone.status()['name'].replace(u"’","'"))
            #mic.say("Did you mean the {type} named {name}?".format(type=phone.status()['deviceDisplayName'], name=(phone.status()['name'].replace("’".decode('utf-8'),"'"))))
            #command = mic.activeListen()
            #if any(aff in command for aff in AFFIRMATIVE):
            phone_to_ring = phone
            break

    # Just one
    elif len(iphones) == 1:
        phone_to_ring = iphones[0]

    if not phone_to_ring:
        mic.say("You didn't select an iPhone")
        return

    phone_to_ring.play_sound()
    mic.say("Sending ring command to the phone now")
  devices = api.trusted_devices

  for i in range(len(devices)):
    print(str(i) + '. ' + devices[i]['phoneNumber'])

  deviceId = int(input('Enter the device index #: '))
  device = devices[deviceId]

  if not api.send_verification_code(device):
    print('Failed to send verification code.')
    exit(1)

  while True:
    code = click.prompt('Enter the verification code')
    if api.validate_verification_code(device, code):
      break
    else:
      print('Invalid verification code.')

from datetime import datetime, timedelta
from gspread import authorize
from oauth2client.service_account import ServiceAccountCredentials
from numpy import array
import pytz

# how to change day for next month
next_day = datetime.now()
next_day = datetime.now() + timedelta(days=1)

# get all events for the next day from icloud calendar
Exemplo n.º 34
0
class Iftp(cmd.Cmd):
    def __init__(self):
        cmd.Cmd.__init__(self)
        self._sort = True
        self.prompt = "iftp> "
        self._api = None
        self._netrc = netrc.netrc()
        self.path = []
        self.user_path = "/"

    def do_login(self, args):
        """Login into iCloud"""
        try:
            self.username, _, self.password = self._netrc.authenticators(
                "icloud")
        except TypeError:
            self.username = click.prompt("iCloud Username")
            self.password = click.prompt("iCloud Password")
        self._login()

    def do_ls(self, args):
        """List files"""
        if not self.check_login():
            print("Not logged in, login first")
            return

        if args == '':
            args = self.user_path
        else:
            args = os.path.normpath(os.path.join(self.user_path, args))
        path = self._get_handle_for_path(args)
        if path:
            for item in path.dir():
                drive_file = path[item]
                if drive_file.type == "file":
                    perms = "-rw-rw-rw-"
                    size = drive_file.size
                    date = drive_file.date_modified
                    if date.year == datetime.datetime.now().year:
                        filedate = date.strftime("%b %d %H:%S")
                    else:
                        filedate = date.strftime("%b %d  %Y")
                elif drive_file.type == "folder":
                    perms = "drwxrwxrwx"
                    size = 0
                    filedate = "Jan 01  1970"
                print("%s %-4s %5s %-5s %13s %s %s" %
                      (perms, 0, os.getuid(), os.getgid(), size, filedate,
                       drive_file.name))
        return

    def do_get(self, args):
        """Download file"""
        if not self.check_login():
            print("Not logged in, login first")
            return

        args = os.path.normpath(os.path.join(self.user_path, args))
        drive_handle = self._get_handle_for_path(args)
        if drive_handle and drive_handle.type == 'file':
            starttime = time.time()
            with drive_handle.open(stream=True) as response:
                with open(drive_handle.name, "wb") as file_out:
                    copyfileobj(response.raw, file_out)
            stoptime = time.time()
            duration = stoptime - starttime
            print("%s bytes received in %f secs (%f Kbytes/sec)" %
                  (drive_handle.size, duration,
                   drive_handle.size / duration / 1024))
        else:
            print("550 Failed to open file.")
        return

    def do_put(self, args):
        """Download file"""
        if not self.check_login():
            print("Not logged in, login first")
            return

        args = shlex.split(args)
        if len(args) == 1:
            sfile = args[0]
            dfile = os.path.basename(sfile)
        else:
            (sfile, dfile) = args

        head, tail = os.path.split(dfile)
        if head:
            drive_handle = self._get_handle_for_path(
                os.path.normpath(os.path.join(self.user_path, head)))
        else:
            drive_handle = self._get_handle_for_path(self.user_path)

        if drive_handle and drive_handle.type == 'folder':
            size = os.path.getsize(sfile)
            starttime = time.time()
            with open(sfile, 'rb') as file_in:
                drive_handle.upload(file_in)
            stoptime = time.time()
            duration = stoptime - starttime
            print("%s bytes sent in %f secs (%f Kbytes/sec)" %
                  (size, duration, size / duration / 1024))
        return

    def do_mkdir(self, args):
        """Create new directory"""
        if not self.check_login():
            print("Not logged in, login first")
            return

        head, tail = os.path.split(args)
        if head:
            drive_handle = self._get_handle_for_path(
                os.path.normpath(os.path.join(self.user_path, head)))
        else:
            drive_handle = self._get_handle_for_path(self.user_path)
        if drive_handle and drive_handle.type == 'folder':
            drive_handle.mkdir(tail)
        print('257 "%s" created' %
              os.path.normpath(os.path.join(self.user_path, head, tail)))

    def do_rmdir(self, args):
        """Delete a directory"""
        if not self.check_login():
            print("Not logged in, login first")
            return

        args = os.path.normpath(os.path.join(self.user_path, args))
        drive_handle = self._get_handle_for_path(args)
        if drive_handle and drive_handle.type == 'folder':
            drive_handle.delete()
            print("250 Remove directory operation successful.")
        else:
            print("550 Remove directory operation failed.")

    def do_delete(self, args):
        """Delete a file"""
        if not self.check_login():
            print("Not logged in, login first")
            return

        args = os.path.normpath(os.path.join(self.user_path, args))
        drive_handle = self._get_handle_for_path(args)
        if drive_handle and drive_handle.type == 'file':
            drive_handle.delete()
            print("250 Delete operation successful.")
        else:
            print("550 Delete operation failed.")

    def do_rename(self, args):
        """Rename a file or folder"""
        if not self.check_login():
            print("Not logged in, login first")
            return

        sfile, dfile = shlex.split(args)
        args = os.path.normpath(os.path.join(self.user_path, sfile))
        drive_handle = self._get_handle_for_path(args)
        drive_handle.rename(os.path.basename(dfile))
        print("250 Rename successful.")

    def do_pwd(self, args):
        """Show current directory"""
        if not self.check_login():
            print("Not logged in, login first")
            return

        print('%s "%s"' % (257, self.user_path))

    def do_cd(self, args):
        """Change directory"""
        if not self.check_login():
            print("Not logged in, login first")
            return

        path = os.path.normpath(os.path.join(self.user_path, args))
        drive_handle = self._get_handle_for_path(path)
        if drive_handle and drive_handle.type == "folder":
            print('%s "%s"' % (250, "Directory successfully changed."))
            self.user_path = path
        else:
            print("%s %s" % (550, "Failed to change directory."))
        return

    def do_quit(self, args):
        return -1

    def do_EOF(self, args):
        return -1

    def check_login(self):
        if self._api is None:
            return False
        return True

    def _login(self):
        self._api = PyiCloudService(self.username, self.password)

        if self._api.requires_2sa:
            print(
                "Two-factor authentication required. Your trusted devices are:"
            )
            devices = self._api.trusted_devices
            for i, device in enumerate(devices):
                print("  %s: %s" % (
                    i,
                    device.get("deviceName", "SMS to %s") %
                    device.get("phoneNumber"),
                ))

            device = click.prompt("Which device would you like to use?",
                                  default=0)
            device = devices[device]
            if not self._api.send_verification_code(device):
                print("Failed to send verification code")
                sys.exit(1)

            code = click.prompt("Please enter validation code")
            if not self._api.validate_verification_code(device, code):
                print("Failed to verify verification code")
                sys.exit(1)
        print("Logged into iCloud Drive as %s" % self.username)

    def _verify_path(self, path):
        pass

    def _get_handle_for_path(self, args):
        """Get a drive API handle for a path"""
        drive_handle = self._api.drive

        # Handle '/' and just return the base drive_handle
        if args.strip() == '/':
            return drive_handle

        tmppath = args.split("/")
        # Cut leading /
        if tmppath[0] == "" and len(tmppath) > 1:
            tmppath.pop(0)

        try:
            for element in tmppath:
                drive_handle = drive_handle[element]
            return drive_handle
        except KeyError:
            return False