-1

i have been searching for a good solution where I copied code used in an API from postman and tried to use it in Xamarin forms. Problem is that there is a method in the API that generates "signatures", which they do in JS. I have tried various solutions but it does not generate the same message.

In JS =

(function () { 
var timestamp = getTime();
pm.environment.set("timestamp",timestamp);
var clientId = pm.environment.get("client_id");
var secret = pm.environment.get("secret");
var sign = calcSign(clientId,secret,timestamp);
pm.environment.set('easy_sign', sign);
})();

function getTime(){
    var timestamp = new Date().getTime();
    return timestamp;
}

function calcSign(clientId,secret,timestamp){
    var str = clientId + timestamp;
    var hash = CryptoJS.HmacSHA256(str, secret);
    var hashInBase64 = hash.toString();
    var signUp = hashInBase64.toUpperCase();
    return signUp;
}

In C# =

public void timeStamp()
    {
        /*
         *  var str = clientId + timestamp;
            var hash = CryptoJS.HmacSHA256(str, secret);
            var hashInBase64 = hash.toString();
            var signUp = hashInBase64.toUpperCase();
            return signUp;
        */

        var timestamp = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
        var t = (DateTime.Now.ToUniversalTime() - timestamp);
        time = t.ToString();

        
        //CalcSign
        var str = clientID + t;
        var key = Convert.FromBase64String(secret);
        //var key = Convert.FromBase64String(str);
        Console.Write("key:");
        prtByte(key);

        var provider = new System.Security.Cryptography.HMACSHA256(key);
        var hash = provider.ComputeHash(Encoding.UTF8.GetBytes(str));
        Console.Write("hash:");
        prtByte(hash);

        var signature = Convert.ToBase64String(hash);
        Console.WriteLine("signature:" + signature);
        var signUp = signature.ToUpper();
        sign = signUp;
    }

    

    public static void prtByte(byte[] b)
    {
        for (var i = 0; i < b.Length; i++)
        {
            Console.Write(b[i].ToString("x2"));
        }
        Console.WriteLine();
    }

The message i get back is = "The request time is invalid".

omarT
  • 1
  • 2
  • have you compared each element of the signature in both environments to see which specific ones do not match? – Jason Dec 15 '20 at 15:55
  • this `time = t.ToString();` will return a very different value in C# than the corresponding code in JS. – Jason Dec 15 '20 at 15:57
  • Hmm... how else can i add the header to the request? (request.AddHeader("t", "1607953974655"); It needs to be a string, what should i do if the problem lies here? – omarT Dec 15 '20 at 17:26
  • you need to format the time string correctly - C# provides a wide variety of well documented formatting options, and I'm sure there are many existing questions that describe exactly how to format a C# date like JS does – Jason Dec 15 '20 at 17:35
  • https://www.google.com/search?q=c%23+convert+datetime+to++javascript+site:stackoverflow.com – Jason Dec 15 '20 at 18:27
  • I tried this solution: var timestamp = (DateTime.Now.ToUniversalTime() - new DateTime(1970, 1, 1)); var t = (int)(timestamp.TotalMilliseconds + 0.5); time = t; But it still didn't work, when i parsed it to string however i just did this ""+time. Might that be the problem? – omarT Dec 15 '20 at 22:01
  • I have no idea. Have you tried what I suggested 6 hours ago and actually compared the values generated by JS and C# to see if they match? – Jason Dec 15 '20 at 22:15
  • Well, they look alike. But they are different due to the difference in time. So i dont know how to get the same value from postman exactly as in c#, but they do look alike. The main thing i want to achieve is a successful generated token in the api request. I am currently awating a response from tuya customer service (the "creators" of the api) – omarT Dec 15 '20 at 23:01
  • The only way is compare the two generated stings and find the difference. – nevermore Dec 16 '20 at 08:43
  • @JackHua-MSFT but how can i possibly know the difference? Even if i press on postman the http trigger twice in less than 1 sec, there will be a difference. – omarT Dec 16 '20 at 17:27
  • The tuya service desk just told me to "take a look on my timestamp". I tried: var timestamp = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); time = String.Format("",timestamp.TotalMilliseconds + 0.5); But it still doesnt work – omarT Dec 16 '20 at 17:42
  • Print the timestamp in js and c#, then check the difference. – nevermore Dec 17 '20 at 06:23
  • var timestamp = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); Console.WriteLine("Timestamp = "+timestamp.ToString()); var t2 = String.Format("{0}",timestamp.TotalMilliseconds); var t = Double.Parse(t2); var t3 = Convert.ToInt64(t); time =""+ t3; Console.WriteLine("Time = " + time); The output = 1608211527711 - C# 1608223784497 - JS – omarT Dec 17 '20 at 16:51

1 Answers1

0

After a lot of troubleshooting and help from @Jason and @Jack Hua the problem was solved by using DateTime.UtcNow, formatting with String.Format, converting the values first to double and then to int, shown below.

var timestamp = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
Console.WriteLine("Timestamp = "+timestamp.ToString());
var t2 = String.Format("{0}",timestamp.TotalMilliseconds);     
var t = Double.Parse(t2);
var t3 = Convert.ToInt64(t);
time =""+ t3;

Now I only need to solve my other issue "sign invalid", but that is another question. Cheers!!

omarT
  • 1
  • 2