Open malmeloo opened 10 months ago
I doubt this can be included in the pypi package, since building pyprovision requires a D compiler which is not really a default install usually. This might be possible however (on x86-64) if this could run with cosmopolitan: https://github.com/Smoothstep/apple-gen/issues/1 (and if they finally add anisette support)
I have don't have much experience with lower-lever languages, but I was actually messing with this yesterday and it's pretty simple to build a python wheel that includes libprovision.so. The downside is that it still relies on externally installed libraries; I did briefly try to "repair" the wheel using https://github.com/pypa/auditwheel, but it wasn't able to find all external dependencies. That would still require a separate wheel for each architecture / OS / python version though, and would probably be tricky in terms of licensing, to say the least.
That project looks quite interesting though, worth keeping an eye at!
I've just made https://github.com/JayFoxRox/pyprovision-uc public. I'm not sure when I'll get around to finalizing and packaging it up. For now, you can probably install it via pip git install:
pip3 install --user -U git+https://github.com/JayFoxRox/pyprovision-uc.git#egg=pyprovision-uc
I made this when I wasn't able to make pyprovision / D compiler work on my setup within a couple of hours.
It's still unfinished and still needs to be cleaned up. But I've been using a version of this (similar to the one I made public) for a couple of weeks by now.
I had a lot of problems with the stat
syscall emulation, so the code is particularly unclean there.
There's also good chances that there's issues with endianess or 32-bit (because I'm using host ctypes
for ARM guest code).
I'm running this on macOS on M1 (so far) and most things appear to be right.
I'll move my local installation to a raspberry pi 4 soon (and plan to test armv7 soon and aarch64 in a couple of weeks) - I'll fix up any issues I'll find.
There's also a chance that the VM will become unstable over time. The emulated memory layout shows that I had to workaround some of the worst issues. So what I have working now is the bare minimum. I usually spawn a new Python process for every request, so improving it much further is not of interest to me.
I also plan to modify the API a bit in the future - I don't like how it operates on a real filesystem.
Also CC @Dadoum and @biemster
Oh that's really cool! I just tried it out myself and while I did have to fix some things (create the directories, some debugPrint
issues), it runs perfectly otherwise. Most of the code looks like black magic to me, but if you need help with anything else (refactoring?) let me know.
I was able to make dadoum (D written) work in my dockerfile:
FROM python:3.11-slim
RUN pip install --upgrade pip
ENV DEBIAN_FRONTEND=noninteractive
RUN apt update && apt install dub git gcc -y
RUN git clone https://github.com/Dadoum/pyprovision /tmp/pyprovision
RUN cd /tmp/pyprovision && pip install .
...
And I managed (I believe) to write the LocalAnisetteProvider:
class LocalAnisetteProvider(BaseAnisetteProvider):
"""Anisette provider. Generates headers without a remote server using pyprovision."""
def __init__(self, libary_path, provisioning_path, device_json_path):
self.adi = ADI(libary_path)
self.adi.provisioning_path = provisioning_path
self.device = Device(device_json_path)
if not self.device.initialized:
# Pretend to be a MacBook Pro
self.device.server_friendly_description = "<MacBookPro13,2> <macOS;13.1;22C65> <com.apple.AuthKit/1 (com.apple.dt.Xcode/3594.4.19)>"
self.device.unique_device_identifier = str(uuid.uuid4()).upper()
self.device.adi_identifier = secrets.token_hex(8).lower()
self.device.local_user_uuid = secrets.token_hex(32).upper()
self.adi.identifier = self.device.adi_identifier
self.dsid = c_ulonglong(-2).value
self.provisioning_session = ProvisioningSession(self.adi, self.device)
self.provisioning_session.provision(self.dsid)
self.otpObj = self.adi.request_otp(self.dsid)
@property
@override
def otp(self) -> str:
return self.otpObj.one_time_password
@property
@override
def machine(self) -> str:
return self.otpObj.machine_identifier
@override
async def close(self) -> None:
"""See `BaseAnisetteProvider.close`_."""
Based of @dadoum's example... but I get this error:
email? >****
passwd? > ****
Traceback (most recent call last):
File "/app/_login.py", line 77, in get_account_sync
with acc_store.open() as f:
^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/pathlib.py", line 1044, in open
return io.open(self, mode, buffering, encoding, errors, newline)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
FileNotFoundError: [Errno 2] No such file or directory: 'account.json'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/app/do_login.py", line 13, in <module>
acc = get_account_sync(anisette)
^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/app/_login.py", line 80, in get_account_sync
_login_sync(acc)
File "/app/_login.py", line 20, in _login_sync
state = account.login(email, password)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/site-packages/findmy/reports/account.py", line 960, in login
return self._evt_loop.run_until_complete(coro)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/asyncio/base_events.py", line 654, in run_until_complete
return future.result()
^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/site-packages/findmy/reports/account.py", line 468, in login
new_state = await self._gsa_authenticate(username, password)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/site-packages/findmy/reports/account.py", line 731, in _gsa_authenticate
raise InvalidCredentialsError(msg)
findmy.errors.InvalidCredentialsError: Password authentication failed: This action could not be completed due to possible environment mismatch.
Exception ignored in: <function Closable.__del__ at 0x7aeb37d64400>
Traceback (most recent call last):
File "/usr/local/lib/python3.11/site-packages/findmy/util/closable.py", line 31, in __del__
AttributeError: 'LocalAnisetteProvider' object has no attribute '_loop'
ERROR:asyncio:Unclosed client session
client_session: <aiohttp.client.ClientSession object at 0x7aeb3794fc50>
ERROR:asyncio:Unclosed connector
connections: ['[(<aiohttp.client_proto.ResponseHandler object at 0x7aeb37bb73f0>, 1307.841477031)]']
connector: <aiohttp.connector.TCPConnector object at 0x7aeb3794ff50>
findmy.errors.InvalidCredentialsError: Password authentication failed: This action could not be completed due to possible environment mismatch.
Any clue? I know that this is not even implemented, but maybe knows what this error indicates. Also, If what I did can help you, I can try and open a PR...
@hkfuertes you might want to change your password, people subscribed to this got it in their email.
Thank you! It was a mistake... I didn't thought of email subscription...
Edit: Changed!, @biemster thank you for the heads up!
I think I'm able to answer myself: https://github.com/malmeloo/FindMy.py/blob/d82b1fbda590e28b17bcae2649b7b9c987e4b056/findmy/reports/anisette.py#L71
😆 I'll keep working... I'm trying to make a flask API compatible with OpenHaystack Mobile app, to be able to track my airtags from android...
Oh yes indeed, sorry for taking so long to respond. But glad you figured it out yourself!
The issue here is not necessarily getting local anisette to work, but rather packaging it so that people don't need a local D compiler. Unless your solution works outside of Docker as well?
Edit: you could also use anisette-v3-server in a separate docker container if you're deploying FindMy.py in docker anyway; that way you can simply use RemoteAnisetteProvider
with the container's ip address.
Also also, if you have a functional API implementation, let me know because I'm also interested ;-)
Ohhh I'm way behind you guys... hahahaha I just now how to follow steps and connect dots, I dont really understand Anisette or Findmy... hahahahah.
The only reason I tried the local anisette is just to try... you see, I tried remote anisete with the anisette server in the same docker-compose, and it worked fine... but only after first login. Once I restart the server, for some reason, I needed to re-login. I was hoping that local anisette would solve this issue...
Support local anisette header generation using pyprovision.