Page 1 of 2 12 LastLast
Results 1 to 10 of 16

Thread: Programming using v5 commands. How to login?

  1. #1
    Join Date
    Sep 2013
    Location
    USA
    Posts
    184

    Programming using v5 commands. How to login?

    I have a ton of utilities and a client that I am dragging up to v5 compatibility. All of them currently read and/or modify the database directly and I am trying to get away from that using the http calls.
    I know you are super busy and I'm trying to bug you as little as possible. Right now I am trying to learn by reproducing the calls that the web client makes.
    My question is this: Do I need to login to use calls like: "/services/service?method=channel.list&format=json"? or is logging in irrelevant for applications?

    When the web page logs in, it gets a return code of 302.
    When I login using the code below, I get a return code of 200. Yet, I can get a channel listing.
    So, I am confused at this point. Did I login successfully? Do I need to login at all? Did I get the channel listing because I am already logged in with the web interface in chrome? How do I log out?

    Code:
     
            //function doLogin()
            //{
            //    var salt = getParameterByName("salt");
            //    var username = $("#email").val();
            //    var password = MD5($("#password").val());
            //    var combined = MD5(salt + ":" + username + ":" + password);
            //    window.location.href = 'login.html?hash=' + combined;
            //}
           
            public async Task<bool> doLogin()
            {
                string url = "http://192.168.86.25:8866";            
                try
                {
                    //login
                    fHttpResponseMsg = await fHttpClient.GetAsync(url);
                    fHttpRequestMsg = fHttpResponseMsg.RequestMessage;
                    string query = fHttpRequestMsg.RequestUri.Query;                
                    var parts = HttpUtility.ParseQueryString(query);
                    string salt = parts.Get("salt");                                
                    string passMD5 = CreateMD5("password").ToLower();
                    string hash = CreateMD5(string.Format("{0}:{1}:{2}", salt, "admin", passMD5));
                    hash = hash.ToLower();
                    string loginRequest = string.Format("{0}/login.html?hash={1}", url, hash);
                    fHttpResponseMsg = await fHttpClient.GetAsync(loginRequest);
                    fHttpRequestMsg = fHttpResponseMsg.RequestMessage;
                    //get channel listing
                    string serviceRequest = string.Format("{0}/services/service?method=channel.list&format=json", url); 
                    fHttpResponseMsg = await fHttpClient.GetAsync(serviceRequest);                
                    string json = await fHttpResponseMsg.Content.ReadAsStringAsync();
                    return true;
                }
                catch 
                {
                    return false;
                }
            }      
    
            public static string CreateMD5(string input)
            {
                // Use input string to calculate MD5 hash. Cut and paste from Stackoverflow
                using (System.Security.Cryptography.MD5 md5 = System.Security.Cryptography.MD5.Create())
                {
                    byte[] inputBytes = System.Text.Encoding.UTF8.GetBytes(input);
                    byte[] hashBytes = md5.ComputeHash(inputBytes);
    
                    // Convert the byte array to hexadecimal string
                    StringBuilder sb = new StringBuilder();
                    for (int i = 0; i < hashBytes.Length; i++)
                    {
                        sb.Append(hashBytes[i].ToString("X2"));
                    }
                    return sb.ToString();
                }
            }
    Thanks for your help!

    JLM

  2. #2
    Join Date
    May 2006
    Location
    Canada
    Posts
    29,170
    Login is a two step operation. The best public source to the HTTP API use is in the kodi pvr plugin. The knewc plugin has similar logic in python, and I will be posting .net code for Emby soon.

    Martin

  3. #3
    Join Date
    Nov 2003
    Location
    NextPVR HQ, Wellington, New Zealand
    Posts
    91,202
    All the api calls require a sid ("session ID") from a logged in session.

    To do the login, the easiest example code to look at is probably the pvr.nextpvr kodi addon code, in the connect() function.
    https://github.com/kodi-pvr/pvr.next...nt-nextpvr.cpp

    Specifically, this bit of code:
    Code:
     if (DoRequest("/service?method=session.initiate&ver=1.0&device=xbmc", response) == HTTP_OK)
      {
        TiXmlDocument doc;
        if (doc.Parse(response.c_str()) != NULL)
        {
          TiXmlElement* saltNode = doc.RootElement()->FirstChildElement("salt");
          TiXmlElement* sidNode = doc.RootElement()->FirstChildElement("sid");
    
          if (saltNode != NULL && sidNode != NULL)
          {
            // extract and store sid
            PVR_STRCLR(m_sid);
            PVR_STRCPY(m_sid, sidNode->FirstChild()->Value());
            NextPVR::m_backEnd->setSID(m_sid);
            // extract salt
            char salt[64];
            PVR_STRCLR(salt);
            PVR_STRCPY(salt, saltNode->FirstChild()->Value());
    
            // a bit of debug
            XBMC->Log(LOG_DEBUG, "session.initiate returns: sid=%s salt=%s", m_sid, salt);
    
    
            std::string pinMD5 = PVRXBMC::XBMC_MD5::GetMD5(g_szPin);
            StringUtils::ToLower(pinMD5);
    
            // calculate combined MD5
            std::string combinedMD5;
            combinedMD5.append(":");
            combinedMD5.append(pinMD5);
            combinedMD5.append(":");
            combinedMD5.append(salt);
    
            // get digest
            std::string md5 = PVRXBMC::XBMC_MD5::GetMD5(combinedMD5);
    
            // login session
            std::string loginResponse;
            char request[512];
            sprintf(request, "/service?method=session.login&sid=%s&md5=%s", m_sid, md5.c_str());
            if (DoRequest(request, loginResponse) == HTTP_OK)
            {
              if (strstr(loginResponse.c_str(), "<rsp stat=\"ok\">"))
              {

  4. #4
    Join Date
    Nov 2003
    Location
    NextPVR HQ, Wellington, New Zealand
    Posts
    91,202
    Basically you call "/service?method=session.initiate" first, which will return you "salt" and "sid" values.

    Next you need to login using "/service?method=session.login", passing through an "md5" value (which was derived a string constructed from the md5(":md5(pin):salt")

  5. #5
    Join Date
    Sep 2013
    Location
    USA
    Posts
    184
    Thanks for the super quick reply!

    JLM

  6. #6
    Join Date
    Sep 2013
    Location
    USA
    Posts
    184
    Ok, so I am here now but get a login failed result...

    In the web interface login you pass MD5("salt:username:MD5(password)")
    but the kodi login consists of MD5(":MD5(password):salt")
    Am I missing where the username comes in for the kodi login?
    Should I be using "device=xmbc" in the request(s)?

    Here's my login code:

    Code:
    //function doLogin()
            //{
            //    var salt = getParameterByName("salt");
            //    var username = $("#email").val();
            //    var password = MD5($("#password").val());
            //    var combined = MD5(salt + ":" + username + ":" + password);
            //    window.location.href = 'login.html?hash=' + combined;
            //}
           
            public async Task<bool> doLogin()
            {
                string url = "http://192.168.86.25:8866";
                string initiate = "{0}/service?method=session.initiate&ver=1.0&device=xbmc&format=json";
                string login = "{0}/service?method=session.login&sid={1}&md5={2}";
    
                try
                {
                    // initiate
                    string httpRequest = string.Format(initiate, url);
                    fHttpResponseMsg = await fHttpClient.GetAsync(httpRequest);
                    fHttpRequestMsg = fHttpResponseMsg.RequestMessage;
                    string loginJson = await fHttpResponseMsg.Content.ReadAsStringAsync();
                    fLoginInfo = JsonConvert.DeserializeObject<tLoginInfo>(loginJson);                
                    // login
                    string passMD5 = CreateMD5("password").ToLower();
                    string s = string.Format(":{0}:{1}", passMD5, fLoginInfo.salt);
                    string hash = CreateMD5(s).ToLower();
                    httpRequest = string.Format(login, url,fLoginInfo.sid, hash);
                    fHttpResponseMsg = await fHttpClient.GetAsync(httpRequest);
                    fHttpRequestMsg = fHttpResponseMsg.RequestMessage;
                    string content = await fHttpResponseMsg.Content.ReadAsStringAsync();
                    
                    return true;
                }
                catch 
                {
                    return false;
                }
            }       
        loginJson = {"sid":"7a1b4019c83e47fd92f6d10dfd99c72f","salt":"48b0df52-2c8f-4eb4-ad7c-6f7ac6aa4c8d"}
        s = :5f4dcc3b5aa765d61d8327deb882cf99:48b0df52-2c8f-4eb4-ad7c-6f7ac6aa4c8d
        hash = e1169a5033aa67a0dc9cbbc05df5dd71
        httpRequest = http://192.168.86.25:8866/service?method=session.login&sid=7a1b4019c83e47fd92f6d10dfd99c72f&md5=e1169a5033aa67a0dc9cbbc05df5dd71
        content = <?xml version="1.0" encoding="utf-8" ?><rsp stat="fail"><err code="1" msg="Login Failed" /></rsp>
    Any ideas?

    JLM

  7. #7
    Join Date
    Nov 2003
    Location
    NextPVR HQ, Wellington, New Zealand
    Posts
    91,202
    Just to be clear - that login takes the pin, not the password. ie, default pin is 0000

  8. #8
    Join Date
    May 2006
    Location
    Canada
    Posts
    29,170
    I can understand the confusion, the API doesn't require the username/password, it is based on the PIN.

    Martin

  9. #9
    Join Date
    Nov 2003
    Location
    NextPVR HQ, Wellington, New Zealand
    Posts
    91,202
    I can look into providing a version of the login api that accepts a username/password. I havn't needed it to date. (the web app uses it's special access to the web server to do a login in a way that another client couldn't easily replicate)

  10. #10
    Join Date
    Sep 2013
    Location
    USA
    Posts
    184
    content = <?xml version="1.0" encoding="utf-8" ?><rsp stat="ok"><sid>481e61328cc54915aa67639973969460</sid></rsp>

    Voila! "A password of '0000' gets me an 'OK'. Now I have to figure out where the sid goes...

    All the api calls require a sid ("session ID") from a logged in session.
    I haven't run across a call beyond login that includes an sid. When and where do you use the sid?

    JLM
    Last edited by drmargarit; 2019-08-05 at 05:16 PM. Reason: added question

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •