Hello everyone,
I’m working on a unity based app that needs to be able to grab a video from an online server and allow users to login to twitter, share it and log out. I’ve spent almost 2 days now trying to get this to work but I’m stumped on this problem now. My app uses the twitterkit for unity and my workflow is as follows:
- Initialize twitter using Twitter.Init
- have user log in when a button is pressed using Twitter.Login()
- in the login success callback call my video upload function passing it the TwitterSession object
- I pull the video file from the server using a standard WWW class and convert it into bytes
- I generate the Authorization header using the consumer keys and the authToken keys and it comes out like this:
OAuth oauth_consumer_key=“", oauth_nonce=“4ArpK0iUiQ7aJERw1EcgDJdVZ64r0eNrSq0HYpGQ”, oauth_signature=“eK5DUWFvhFEplfkHouDMmSr9iP0%3D”, oauth_signature_method=“HMAC-SHA1”, oauth_timestamp=“1501799767”, oauth_token="**”, oauth_version=“1.0”
- Next I start posting the video using the chunk post media method following the Twitter dev documentation by sending a request with this link and attaching the header:
https://upload.twitter.com/1.1/media/upload.json?command=INIT&total_bytes=383631&media_type=video/mp4
I also have code to do the append and the finalize requests but I get the 401 error on this first request I send out. I have tried a lot of different things and read pretty much all of the twitter documentations, Im thinking maybe its the way I am generating the signature key. on the docs it says that the signature key is generated from every other parameter in the header, another page on the docs mention that for media uploads I have to discard the post and url when generating it, I have tried both ways and Im still getting the same error. I’ll post some code here maybe someone can point me to what Im doing wrong.
This is the function that I use to post the video:
IEnumerator StartTwitterVideoUpload(TwitterSession _session)
{
yield return new WaitForEndOfFrame();
WWW www;
WWWForm wwwForm;
byte[] videoBytes;
string mediaID;
string baseurl = "https://upload.twitter.com/1.1/media/upload.json?";
byte[] dummy = new byte[1];
dummy[0] = 0;
parameters = new Dictionary<string, string>();
Hashtable headers = new Hashtable();
headers["Authorization"] = GetHeaderWithAccessToken("POST", baseurl, TwitterKit.Unity.Settings.TwitterSettings.ConsumerKey, TwitterKit.Unity.Settings.TwitterSettings.ConsumerSecret, _session, parameters);
Debug.Log (headers ["Authorization"]);
//init
www = new WWW("ServerLink/test.mp4");
while(!www.isDone) {
yield return null;
debugUI.text = "progress : " + www.progress;
}
debugUI.text = "size : " + www.bytesDownloaded;
videoBytes = www.bytes;
string url = baseurl + "command=INIT&total_bytes=" + www.bytesDownloaded + "&media_type=video/mp4";
www = new WWW (url, dummy, headers);
yield return www;
Debug.Log ("INIT " + www.url);
if (string.IsNullOrEmpty (www.error)) {
//other code here
} else {
//getting error 401 here!
}
This is how I’m generating the signature key:
private static string GenerateSignature(string httpMethod, string url, Dictionary<string, string> parameters)
{
var nonSecretParameters = (from p in parameters
where !SecretParameters.Contains(p.Key)
select p);
string signatureBaseString = string.Format(CultureInfo.InvariantCulture,
"{0}",//&{1}&{2}",
//httpMethod, try without this might not
//UrlEncode(NormalizeUrl(new Uri(url))), be needed for video upload
UrlEncode(nonSecretParameters));
string key = string.Format(CultureInfo.InvariantCulture,
"{0}&{1}",
UrlEncode(parameters["oauth_consumer_secret"]),
parameters.ContainsKey("oauth_token_secret") ? UrlEncode(parameters["oauth_token_secret"]) : string.Empty);
HMACSHA1 hmacsha1 = new HMACSHA1(Encoding.ASCII.GetBytes(key));
byte[] signatureBytes = hmacsha1.ComputeHash(Encoding.ASCII.GetBytes(signatureBaseString));
return Convert.ToBase64String(signatureBytes);
}
And this is the encoding function:
private static string UrlEncode(string value)
{
if (string.IsNullOrEmpty(value))
{
return string.Empty;
}
value = Uri.EscapeDataString(value);
value = Regex.Replace(value, "(%[0-9a-f][0-9a-f])", c => c.Value.ToUpper());
value = value
.Replace("(", "%28")
.Replace(")", "%29")
.Replace("$", "%24")
.Replace("!", "%21")
.Replace("*", "%2A")
.Replace("'", "%27");
value = value.Replace("%7E", "~");
return value;
}
Thank you everyone for your help