watson / airplay-protocol

A low level protocol wrapper on top of the AirPlay HTTP API
MIT License
106 stars 12 forks source link

Device verification forced on Apple TV 4th with latest 10.2 software update #7

Open romaincointepas opened 7 years ago

romaincointepas commented 7 years ago

This is the Apple feature that shows a code on the Apple TV that has to be entered on the AirPlay sender by the user (iPhone, iPad).

As far as I know, this exists for a while but has always been an opt-in option. The 10.2 update makes it forced.

Any plans on supporting this?

Deliaz commented 7 years ago

Looks like the airplay-protocol doesn't work anymore with the latest tvOS 10.2. My Apple TV prompt me to use iTunes 11.2 or newer. But changing USER_AGENT constant in the sources didn't work.

funtax commented 7 years ago

Maybe this project could get some help by Beamer, AirParrot or DoubleTwist? They seem to have managed the hardware verification.

funtax commented 7 years ago

Hey there,

feel free to use my Java-library as a template: https://github.com/funtax/AirPlayAuth

You can simply import the project eg. into "IntelliJ Community Edition" and run the example :)

I'm the developer of two audio AirPlay-apps and can confirm that once the pairing has been done, the ongoing communication with the AirPlay-receiver is done like before.

Also, there seems to be no reliable way to check if pairing is required, beside checking the mdns-data for "appletv" and "pk". Then authentication can also be made on ATVs which have the authentication not enabled, so you can simply always do the pairing in case it's an AppleTV.

Ps. The source of my engineering is a scrambled NodeJS-script (not published) which I could also offer as an unbeautified template. It cointains all parts required for the authentication and could be written well by someone with more Node-knowledge than me. This in combination with the Java-script could solve your issue in a few days.

loretoparisi commented 6 years ago

@funtax thanks! Do you see any difficulties to port AirPlayAuth to javascript? Maybe using crypto this could be tricky:

public static String generateNewAuthToken() {
        String clientId = AuthUtils.randomString(16);

        return clientId + "@" + net.i2p.crypto.eddsa.Utils.bytesToHex(new KeyPairGenerator().generateKeyPair().getPrivate().getEncoded());
    }
funtax commented 6 years ago

@loretoparisi The code has been ported to Python, C and ObjectiveC as far as I know.. so there are several reference-implementations available. I thing porting it into JS should be no major problem. The SRP6a-stuff was the most tricky thing, but one has just to make sure that all the variables do 1:1 the same as in my implementation.

francisco-navarro commented 6 years ago

@funtax I tried your project not working for me, after validate pin, I tried play and:

HTTP/1.1 200 OK Date: Sat, 24 Feb 2018 11:57:08 GMT Content-Length: 0 Content-Type: application/octet-stream Server: AirTunes/356.19

Pair Verify finished! HTTP/1.1 400 Bad Request Content-Length: 0 Server: AirTunes/356.19

It fails in AuthUtils.postData(socket, "/play", "text/parameters", content.getBytes("UTF-8"));

Any idea?

funtax commented 6 years ago

Hey @francisco-navarro , did you directly executed my example, or did you use a modified on? I have my ATV not running at the moment and would have to setup it again first to reproduce your issue :)

francisco-navarro commented 6 years ago

I run your example with modified parameters (ip and new token created). Then I see in the atv the pin and its pair correctly. But when it does the post /play text/parameters url, I get a 400. I was reading documentation about de api, and I can do a GET with info, but the play doesn't work.

funtax commented 6 years ago

Are you able to open the video in your Browser? I think this issue has nothing to do with the authentication but furthermore with some other issues.

2018-02-24 13:42 GMT+01:00 Paco Navarro notifications@github.com:

I run your example with modified parameters (ip and new token created). Then I see in the atv the pin and its pair correctly. But when it does the post /play text/parameters url, I get a 400. I was reading documentation about de api, and I can do a GET with info, but the play doesn't work.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/watson/airplay-protocol/issues/7#issuecomment-368225921, or mute the thread https://github.com/notifications/unsubscribe-auth/AAZmMNag7ExVoiy2Y83JGsU-NBk9Q79Xks5tYAOYgaJpZM4MSZhV .

ViktoriiaKh commented 6 years ago

@francisco-navarro, the play request failed with 400 Bad Request Error because the request body must be of type application/x-apple-binary-plist (text parameters are not supported any more).

funtax commented 6 years ago

Thanks @ViktoriiaKh for the information.

ingsaurabh commented 6 years ago

@ViktoriiaKh can you check that again as it is giving me 400 bad request even if I use "application/x-apple-binary-plist"

ViktoriiaKh commented 6 years ago

@ingsaurabh, I've just re-checked it on my Apple TV (4th generation) and Apple TV 4K with the latest tvOS 11.2.6 installed. And everything works fine.

CLIENT -> SERVER:

POST /play HTTP/1.1
User-Agent: AirPlay/320.20
Content-Type: application/x-apple-binary-plist
Content-Length: 174
X-Apple-Device-ID: 0x0c5ec9b8179c

<BINARY PLIST DATA>

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
 "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
 <dict>
  <key>Content-Location</key>
  <string>http://commondatastorage.googleapis.com/gtv-videos-bucket/big_buck_bunny_1080p.mp4</string>
  <key>Start-Position</key>
  <real>0.1610738</real>
 </dict>
</plist>

SERVER -> CLIENT:

HTTP/1.1 200 OK
Date: Mon, 26 Mar 2018 13:09:08 GMT
Server: AirTunes/356.19
Content-Length: 0
mmm117 commented 6 years ago

@ViktoriiaKh @funtax , I just checked your Xcode version on my Apple TV (4th gen) with the latest tvOS 11.4 installed, it failed to work.. could you please help to check?

If anybody manages to make it work on tvOS 11.4, please help! Thank you!!

dyorgio commented 5 years ago

@ViktoriiaKh Could you show us your code? I can't get it work with binary plist format (http 500 response). Do I need to include on body ""?

@funtax Can you update your project with new "application/x-apple-binary-plist" requeriment?

koush commented 4 years ago

I'm trying to get this working, and had the error 400 before. After switching to a binary plist, I now have an error 500.

        NSDictionary plist = new NSDictionary();
        plist.put("Content-Location", "http://techslides.com/demos/sample-videos/small.mp4");
        plist.put("Start-Position", 0.0);
        byte[] contentBytes = BinaryPropertyListWriter.writeToArray(plist);

        AuthUtils.postData(socket, "/play", "application/x-apple-binary-plist", contentBytes);
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Content-Location</key>
    <string>http://techslides.com/demos/sample-videos/small.mp4</string>
    <key>Start-Position</key>
    <real>0.0</real>
</dict>
</plist>

Update:

It seems to work every now and then, maybe 10% of the time if a debugger is attached. Some race condition maybe?