Unauthorized Error on image upload but not plain texts upload

dotnet
csharp

#1

Plain text tweets get uploaded successfully. But when I need to add images to a tweet I get Unauthorized error when uploading the image.

To upload the image, I use this url
upload.twitter.com
This is to get the media_id but unfortunately, I get unauthorised error.

Please what am I doing wrongly


#2

It is very hard to diagnose without more information. Can you share any code to demonstrate the error?

We have a simple Python-based video upload example that may be useful.


#3

Hello Andy, welcome back!

I’m using the TinyTwitter Plugin. But it only sends texts, no images or videos. I tried extending it to include images. Attached is the C# code I’m using.

Whenever I call the INIT procedure, I get unauthorised error.

Please, help me figure out what I’m doing wrong.

Precious


using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;


namespace TinyTwitter
{
    public class OAuthInfo
    {
        public string ConsumerKey { get; set; }
        public string ConsumerSecret { get; set; }
        public string AccessToken { get; set; }
        public string AccessSecret { get; set; }
        //public string authorizeURL { get; set; }
        //public string request_tokenURL { get; set; }
        //public string GrantedPermissionURL { get; set; }
                      
            }

    public class Tweet
    {
        public long Id { get; set; }
        public DateTime CreatedAt { get; set; }
        public string UserName { get; set; }
        public string ScreenName { get; set; }
        public string Text { get; set; }
    }

    public class TinyTwitter
    {
        private readonly OAuthInfo oauth;

        public TinyTwitter(OAuthInfo oauth)
        {
            this.oauth = oauth;
        }
      public string UploadMedia(string ImgExt,string 

fileSize,string fileContent)
        {            
            var res = INIT(ImgExt, fileSize);
            //get media_id from response
            res = APPEND("media_id", fileContent,fileSize);
            if (res == "")
                res = FINALIZE("media_id",fileSize);
            else res = "ERROR: Image not uploaded";
            return res;    
        }
        private string INIT(string ImgExt, string fileSize)
        {
            var contd = new RequestBuilder(oauth, "POST", 

"https://upload.twitter.com/1.1/media/upload.json", "INIT", 

"Image/jpeg",fileSize);
            contd.AddParameter("command", "INIT");
            contd.AddParameter("media_type", "Image/jpeg");
            contd.AddParameter("total_bytes", fileSize);
            //contd.AddParameter("media_category", 

"tweet_image");
            var res= contd.Execute(true);
            //return res("media_id_string");
            return "";
        }

        private string APPEND(string media_id, string 

fileContent,string fileSize)
        {
            var contd = new RequestBuilder(oauth, "POST", 

"https://upload.twitter.com/1.1/media/upload.json", "APPEND", 

"Image/jpeg",fileSize);
            contd.AddParameter("command", "APPEND");
            contd.AddParameter("media_id_string", media_id);
            contd.AddParameter("segment_index", "0");
            contd.AddParameter("media_data", fileContent);
            //contd.AddParameter("file ", filePath);
            contd.AddParameter("file-field", "media");
             return contd.Execute(true);
                   }

        private string FINALIZE(string media_id,string 

fileSize)
        {
            var contd = new RequestBuilder(oauth, "POST", 

"https://upload.twitter.com/1.1/media/upload.json", "FINALIZE", 

"Image/jpeg", fileSize);
            contd.AddParameter("command", "FINALIZE");
            contd.AddParameter("media_id_string", media_id);
            var res = contd.Execute(true);
            //return res("media_id_string");
            return "";
        }

        public void UpdateStatus(string message, string 

media_id=null)
        {
           var req= new RequestBuilder(oauth, "POST", 

"https://api.twitter.com/1.1/statuses/update.json");
           req.AddParameter("status", message);

           if (media_id != null) 
               req.AddParameter("media_id", media_id);

           req.Execute();
        }

        public IEnumerable<Tweet> GetHomeTimeline(long? sinceId 

= null, long? maxId = null, int? count = 20)
        {
            return GetTimeline

("https://api.twitter.com/1.1/statuses/home_timeline.json", 

sinceId, maxId, count, "");
        }

        public IEnumerable<Tweet> GetMentions(long? sinceId = 

null, long? maxId = null, int? count = 20)
        {
            return GetTimeline

("https://api.twitter.com/1.1/statuses/mentions.json", sinceId, 

maxId, count, "");
        }

        public IEnumerable<Tweet> GetUserTimeline(long? sinceId 

= null, long? maxId = null, int? count = 20, string screenName 

= "")
        {
            return GetTimeline

("https://api.twitter.com/1.1/statuses/user_timeline.json", 

sinceId, maxId, count, screenName);
        }

        private IEnumerable<Tweet> GetTimeline(string url, 

long? sinceId, long? maxId, int? count, string screenName)
        {
            var builder = new RequestBuilder(oauth, "GET", 

url);

            if (sinceId.HasValue)
                builder.AddParameter("since_id", 

sinceId.Value.ToString());

            if (maxId.HasValue)
                builder.AddParameter("max_id", 

maxId.Value.ToString());

            if (count.HasValue)
                builder.AddParameter("count", 

count.Value.ToString());

            if (screenName != "")
                builder.AddParameter("screen_name", 

screenName);

            var responseContent = builder.Execute();

            var serializer = new 

System.Web.Script.Serialization.JavaScriptSerializer();

            var tweets = (object[])

serializer.DeserializeObject(responseContent);

            return tweets.Cast<Dictionary<string, object>>

().Select(tweet =>
            {
                var user = ((Dictionary<string, object>)tweet

["user"]);
                var date = DateTime.ParseExact(tweet

["created_at"].ToString(),
                    "ddd MMM dd HH:mm:ss zz00 yyyy",
                    CultureInfo.InvariantCulture).ToLocalTime

();

                return new Tweet
                {
                    Id = (long)tweet["id"],
                    CreatedAt = date,
                    Text = (string)tweet["text"],
                    UserName = (string)user["name"],
                    ScreenName = (string)user["screen_name"]
                };
            }).ToArray();
        }

        #region RequestBuilder

        public class RequestBuilder
        {
            private const string VERSION = "1.0";
            private const string SIGNATURE_METHOD = "HMAC-

SHA1";

            private readonly OAuthInfo oauth;
            private readonly string method;
            private readonly IDictionary<string, string> 

customParameters;
            private readonly string url;
            private readonly string command;
            private readonly string total_bytes;
            private readonly string media_type;

            public RequestBuilder(OAuthInfo oauth, string 

method, string url,string command=null,string media_type=null, 

string total_bytes=null)
            {
                this.oauth = oauth;
                this.method = method;
                this.url = url;
                this.command = command;
                this.media_type = media_type;
                this.total_bytes = total_bytes;
                customParameters = new Dictionary<string, 

string>();
            }

            public RequestBuilder AddParameter(string name, 

string value)
            {
                customParameters.Add(name, value.EncodeRFC3986

());
                return this;
            }

            public string Execute(Boolean isMedia=false)
            {
                var timespan = GetTimestamp();
                var nonce = CreateNonce();

                var parameters = new Dictionary<string, 

string>(customParameters);
                AddOAuthParameters(parameters, timespan, 

nonce);

                var signature = GenerateSignature(parameters);
                var headerValue = 

GenerateAuthorizationHeaderValue(parameters, signature);

                var request = (HttpWebRequest)

WebRequest.Create(GetRequestUrl());
                request.Method = method;
                request.ContentType = "application/x-www-form-

urlencoded";
                request.Headers.Add("Authorization", 

headerValue);
                if (isMedia) {
                    request.ContentType = "multipart/form-

data";
                    var multipart = 

GenerateMultipartHeaderValue(parameters);
                    request.Headers.Add("multipart", 

multipart);
                }

                

                WriteRequestBody(request);

                // It looks like a bug in HttpWebRequest. It 

throws random TimeoutExceptions
                // after some requests. Abort the request seems 

to work. More info: 
                // 

http://stackoverflow.com/questions/2252762/getrequeststream-

throws-timeout-exception-randomly

                var response = request.GetResponse();

                string content;

                using (var stream = response.GetResponseStream

())
                {
                    using (var reader = new StreamReader

(stream))
                    {
                        content = reader.ReadToEnd();
                    }
                }

                request.Abort();

                return content;
            }

            private void WriteRequestBody(HttpWebRequest 

request)
            {
                if (method == "GET")
                    return;

                var requestBody = Encoding.ASCII.GetBytes

(GetCustomParametersString());
                using (var stream = request.GetRequestStream())
                    stream.Write(requestBody, 0, 

requestBody.Length);
            }

            private string GetRequestUrl()
            {
                if (method != "GET" || customParameters.Count 

== 0)
                    return url;

                return string.Format("{0}?{1}", url, 

GetCustomParametersString());
            }

            private string GetCustomParametersString()
            {
                return customParameters.Select(x => 

string.Format("{0}={1}", x.Key, x.Value)).Join("&");
            }

            private string GenerateAuthorizationHeaderValue

(IEnumerable<KeyValuePair<string, string>> parameters, string 

signature)
            {
                return new StringBuilder("OAuth ")
                    .Append(parameters.Concat(new 

KeyValuePair<string, string>("oauth_signature", signature))
                                .Where(x => x.Key.StartsWith

("oauth_"))
                                .Select(x => string.Format

("{0}=\"{1}\"", x.Key, x.Value.EncodeRFC3986()))
                                .Join(","))
                    .ToString();
            }

            private string GenerateMultipartHeaderValue

(IEnumerable<KeyValuePair<string, string>> parameters)
            {
                return new StringBuilder()
                    .Append(command).Append("&")
                    .Append(total_bytes).Append("&")
                    .Append(media_type.EncodeRFC3986()).Append

("&")
                    .Append(parameters
                                .OrderBy(x => x.Key)
                                .Select(x => string.Format

("{0}={1}", x.Key, x.Value))
                                .Join("&")
                                .EncodeRFC3986()).ToString();
                            }

            private string GenerateSignature

(IEnumerable<KeyValuePair<string, string>> parameters)
            {
                var dataToSign = new StringBuilder()
                    .Append(method).Append("&")
                    .Append(url.EncodeRFC3986()).Append("&")
                    .Append(parameters
                                .OrderBy(x => x.Key)
                                .Select(x => string.Format

("{0}={1}", x.Key, x.Value))
                                .Join("&")
                                .EncodeRFC3986());

                var signatureKey = string.Format("{0}&{1}", 

oauth.ConsumerSecret.EncodeRFC3986(), 

oauth.AccessSecret.EncodeRFC3986());
                var sha1 = new HMACSHA1

(Encoding.ASCII.GetBytes(signatureKey));

                var signatureBytes = sha1.ComputeHash

(Encoding.ASCII.GetBytes(dataToSign.ToString()));
                return Convert.ToBase64String(signatureBytes);
            }

            private void AddOAuthParameters(IDictionary<string, 

string> parameters, string timestamp, string nonce)
            {
                parameters.Add("oauth_version", VERSION);
                parameters.Add("oauth_consumer_key", 

oauth.ConsumerKey);
                parameters.Add("oauth_nonce", nonce);
                parameters.Add("oauth_signature_method", 

SIGNATURE_METHOD);
                parameters.Add("oauth_timestamp", timestamp);
                parameters.Add("oauth_token", 

oauth.AccessToken);
                                            }

            private static string GetTimestamp()
            {
                return ((int)(DateTime.UtcNow - new DateTime

(1970, 1, 1)).TotalSeconds).ToString();
            }

            private static string CreateNonce()
            {
                return new Random().Next(0x0000000, 

0x7fffffff).ToString("X8");
            }
        }

        #endregion
    }

    public static class TinyTwitterHelperExtensions
    {
        public static string Join<T>(this IEnumerable<T> items, 

string separator)
        {
            return string.Join(separator, items.ToArray());
        }

        public static IEnumerable<T> Concat<T>(this 

IEnumerable<T> items, T value)
        {
            return items.Concat(new[] { value });
        }

        public static string EncodeRFC3986(this string value)
        {
            // From Twitterizer http://www.twitterizer.net/

            if (string.IsNullOrEmpty(value))
                return string.Empty;

            var encoded = Uri.EscapeDataString(value);

            return Regex
                .Replace(encoded, "(%[0-9a-f][0-9a-f])", c => 

c.Value.ToUpper())
                .Replace("(", "%28")
                .Replace(")", "%29")
                .Replace("$", "%24")
                .Replace("!", "%21")
                .Replace("*", "%2A")
                .Replace("'", "%27")
                .Replace("%7E", "~");
        }
    }
}

#4

OK, I’m not super familiar with C# but I’ve downloaded Visual Studio for Mac - your code doesn’t have a Main method, and since I’m only able to target .NET Core, System.Web.Script is not found.

My method to work through this would be to run the Python sample and look at the packets it sends, and compare to what your code is doing instead. That’s the best I can suggest for now.


#5

Please add system.web.extensions to your references it will fix the system.web.script error

To send plain text tweet, use the function “UpdateStatus(string message, string media_id=null)”

To first send an image/video, use the partially finished function UploadMedia(string ImgExt,string fileSize,string fileContent). It will call the INIT, APPEND and FINALIZE functions and finally return a media_id that you will supply to the “UpdateStatus(string message, string media_id=null)”.

Hope this is informative enough.

I look forward to hearing from you.


#6

Unfortunately system.web.extensions is not available on .NET Core on a Mac, so that doesn’t work and I’m unable to reproduce what you’re trying to do.

We’re unable to provide comprehensive support across every possible coding language here - I’d suggest maybe raising an issue against the TinyTwitter project on Github, the original author may be able to help.