davidteather / TikTok-Api

The Unofficial TikTok API Wrapper In Python
https://davidteather.github.io/TikTok-Api
MIT License
4.87k stars 977 forks source link

[BUG] - Incorrect signature generation #642

Closed oskardve closed 3 years ago

oskardve commented 3 years ago

Describe the bug

I am working on c# tiktok api for personal use based on your api and everything goes fine until the signature is used in practice, before that it is generated using a script from your API and selenium, everything seems ok but when I try to use the signature in practice, i.e. extract data from endpoint im receiving an empty response from the server with code 200, no error but also no text. Can you help me somehow? Is it some security against bots? Should i do something more?

Edit. I decided to check if it works if I use playwright so i rewrited a whole browser class, but the result was the same, I still get the code 200 and an empty response from the server.

The buggy code

Please insert the code that is throwing errors or is giving you weird unexpected results.

Below is my implementation of your code (Of course, earlier in the code I inject js with acrawler)

public (string, string, string) sign_url(string api_url, string verifyFp = "verify_khr3jabg_V7ucdslq_Vrw9_4KPb_AJ1b_Ks706M8zIJTq", string custom_did = null)
        {
            if (api_url == string.Empty) { DataParse.logData("Sign_url required a api_url parameter"); return (string.Empty, string.Empty, string.Empty); }
            if (verifyFp == string.Empty || custom_did == string.Empty) { DataParse.logData("verifyFp & custom_did are required parameters"); return (string.Empty, string.Empty, string.Empty); }

            string url = $"{api_url}&verifyFp={verifyFp}&did={custom_did}";

            string signature = ((IJavaScriptExecutor)__driver).ExecuteScript("return window.byted_acrawler.sign({url: '" + url + "'});").ToString();

            return (verifyFp, custom_did, signature);
        }

Edit cont. Rewrited sign_url function but now using playwright (still same result)

public async Task<(string, string, string)> sign_url(string api_url, string verifyFp = "verify_khr3jabg_V7ucdslq_Vrw9_4KPb_AJ1b_Ks706M8zIJTq", string custom_did = null)
        {
            // Check if parameters are valid
            if (api_url == string.Empty) { Console.WriteLine("Sign_url required a api_url parameter"); return (string.Empty, string.Empty, string.Empty); }
            if (verifyFp == string.Empty || custom_did == string.Empty) { Console.WriteLine("verifyFp & custom_did are required parameters"); return (string.Empty, string.Empty, string.Empty); }

            // Create new page
            IBrowserContext context;
            IPage page;
            (page, context) = this.create_new_page().Result;
            // Prepare api url
            string url = $"{api_url}&verifyFp={verifyFp}&did={custom_did}";

            // Inject js into page
            await page.SetContentAsync($"<script>{get_acrawler()}</script>");
            var signature = page.EvaluateAsync("() => {var token = window.byted_acrawler.sign({url: '" + url + "'});return token;}").Result.Value.ToString();

            await context.CloseAsync();
            if (!page.IsClosed) await page.CloseAsync();

            // Return data
            return (verifyFp, custom_did, signature);
        }

Original code:

    def sign_url(self, **kwargs):
        url = kwargs.get("url", None)
        if url is None:
            raise Exception("sign_url required a url parameter")

        if kwargs.get("gen_new_verifyFp", False):
            verifyFp = self.gen_verifyFp()
        else:
            verifyFp = kwargs.get(
                "custom_verifyFp",
                "verify_khgp4f49_V12d4mRX_MdCO_4Wzt_Ar0k_z4RCQC9pUDpX",
            )

        if kwargs.get("custom_did") is not None:
            did = kwargs.get("custom_did", None)
        elif self.did is None:
            did = str(random.randint(10000, 999999999))
        else:
            did = self.did

        return (
            verifyFp,
            did,
            self.browser.execute_script(
                '''
        var url = "'''
                + url
                + "&verifyFp="
                + verifyFp
                + """&did="""
                + did
                + """"
        var token = window.byted_acrawler.sign({url: url});
        return token;
        """
            ),
        )

Expected behavior

I thought that I would receive signatures, which, after concating with the API link, will give me the correct response from the server and I will get my data, but I'm receiving an empty responses from the server with the code 200

That's how link with generated signature looks like: https://m.tiktok.com/api/music/item_list/?aid=1988&app_name=tiktok_web&device_platform=web&referer=&root_referer=&user_agent=Mozilla%252F5.0%2B%28iPhone%253B%2BCPU%2BiPhone%2BOS%2B12_2%2Blike%2BMac%2BOS%2BX%29%2BAppleWebKit%252F605.1.15%2B%28KHTML%2C%2Blike%2BGecko%29%2BVersion%252F13.0%2BMobile%252F15E148%2BSafari%252F604.1&cookie_enabled=true&screen_width=794&screen_height=1022&browser_language=&browser_platform=&browser_name=&browser_version=&browser_online=true&ac=4g&timezone_name=&appId=1233&appType=m&isAndroid=False&isMobile=False&isIOS=False&OS=windows&secUid=&musicID=6900010125709413125&count=30&cursor=0&shareUid=&language=en&verifyFp=verify_khr3jabg_V7ucdslq_Vrw9_4KPb_AJ1b_Ks706M8zIJTq&did=8631211774948926517&_signature=_02B4Z6wo00f01VSvdQwAAIBAu7v1doQFFoFUr1GAADXjba

That's how the response from the server looks like. img

Desktop (please complete the following information):

Additional context

oskardve commented 3 years ago

I had a little fun with the playwright browser options and now everything works as it should :)