Пример #1
0
 public TweetController(IHttpClientFactory clientFactory, ILogger <TweetController> logger,
                        IOptions <TwitterOptions> options)
 {
     this.clientFactory = clientFactory;
     this.logger        = logger;
     twitterConf        = options.Value;
 }
 public SubscriptionsService(
     ITwitterClient twitterClient,
     TwitterOptions twitterOptions)
 {
     _twitterClient  = twitterClient;
     _twitterOptions = twitterOptions;
 }
        public void Configure(string name, TwitterOptions options)
        {
            if (!string.Equals(name, TwitterDefaults.AuthenticationScheme))
            {
                return;
            }
            var settings = GetSettingsAsync().GetAwaiter().GetResult();

            options.ConsumerKey = settings.Item1?.ConsumerKey ?? string.Empty;
            try
            {
                options.ConsumerSecret = _dataProtectionProvider.CreateProtector(TwitterConstants.Features.Twitter).Unprotect(settings.Item1.ConsumerSecret);
            }
            catch
            {
                _logger.LogError("The Consumer Secret could not be decrypted. It may have been encrypted using a different key.");
            }

            if (settings.Item2.CallbackPath.HasValue)
            {
                options.CallbackPath = settings.Item2.CallbackPath;
            }
            options.RetrieveUserDetails = true;
            options.SignInScheme        = "Identity.External";
            options.StateCookie.Path    = _tenantPrefix;
        }
Пример #4
0
 void ConfigureTwitterAuthOptions(TwitterOptions opts)
 {
     opts.SignInScheme        = IdentityServerConstants.ExternalCookieAuthenticationScheme;
     opts.ConsumerKey         = _config["Twitter:ConsumerKey"];
     opts.ConsumerSecret      = _config["Twitter:ConsumerSecret"];
     opts.RetrieveUserDetails = true;
 }
Пример #5
0
        static Dictionary <string, string> GetParms(string nonce, string timestamp, TwitterOptions options, bool callBack, bool imageUpload)
        {
            Dictionary <string, string> dic = new Dictionary <string, string>();

            if (callBack)
            {
                dic.Add("oauth_callback", "oob");
            }
            dic.Add(OAUTH_CONSUMER_KEY, Util.EncodeString(options.User.AppSettings.AppKey));
            dic.Add(OAUTH_NONCE, nonce);
            dic.Add(OAUTH_SIGNATURE_METHOD, HMAC_SHA1);
            dic.Add(OAUTH_TIMESTAMP, timestamp);
            dic.Add(OAUTH_VERSION, OAUTH_VERSION_10);
            dic.Add(OAUTH_TOKEN, options.User.OAuthToken);

            if (!imageUpload)
            {
                foreach (var item in options.GetParameters())
                {
                    dic.Add(item.Key, item.Value);
                }
            }

            return(dic);
        }
Пример #6
0
 public WebhooksService(
     ITwitterClient twitterClient,
     TwitterOptions twitterOptions)
 {
     _twitterClient  = twitterClient;
     _twitterOptions = twitterOptions;
 }
Пример #7
0
        private void SetTwitterOptions(TwitterOptions options)
        {
            options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme;
            options.ConsumerKey  = "key";

            options.ConsumerSecret = "secret";
        }
Пример #8
0
        public BaseController(IOptions <TwitterOptions> twitterOptions)
        {
            if (twitterOptions is null)
            {
                throw new ArgumentNullException(nameof(twitterOptions));
            }

            _twitterOptions = twitterOptions.Value;
        }
Пример #9
0
 public WebhookMiddleware(IOptions <TwitterOptions> options, ILogger <WebhookMiddleware> logger, IBot bot,
                          TwitterAdapter adapter)
 {
     _logger      = logger;
     _bot         = bot;
     _adapter     = adapter;
     _options     = options.Value;
     _interceptor = new WebhookInterceptor(_options.ConsumerSecret);
 }
Пример #10
0
 public UIController(ICommandBus commandBus,
                     IOptions <MyUIOptions> uiOptions,
                     IOptions <TwitterOptions> twitterOptions,
                     IGrainFactory grainFactory)
     : base(commandBus)
 {
     this.uiOptions      = uiOptions.Value;
     this.grainFactory   = grainFactory;
     this.twitterOptions = twitterOptions.Value;
 }
Пример #11
0
        public static IApplicationBuilder UseTwitterAuthentication([NotNull] this IApplicationBuilder app, Action <TwitterOptions> configureOptions = null)
        {
            var options = new TwitterOptions();

            if (configureOptions != null)
            {
                configureOptions(options);
            }
            return(app.UseTwitterAuthentication(options));
        }
Пример #12
0
        public async Task <RetrieveTweetsResult> RetrieveTweetsAsync(TwitterOptions options, string key)
        {
            var result    = new RetrieveTweetsResult();
            var tweetList = new List <TweetStruct>();

            if (!string.IsNullOrEmpty(options.Username) && !string.IsNullOrEmpty(options.TwitterConsumerKey) && !string.IsNullOrEmpty(options.TwitterConsumerSecret))
            {
                var bearerToken = ObtainBearerToken(options.TwitterConsumerKey, options.TwitterConsumerSecret);

                var            timelineUrl = string.Format("https://api.twitter.com/1.1/statuses/user_timeline.json?exclude_replies={0}&screen_name={1}", !options.ShowReplies ? "true" : "false", Uri.EscapeDataString(options.Username));
                HttpWebRequest request     = (HttpWebRequest)WebRequest.Create(timelineUrl);
                request.Headers.Add("Authorization", "Bearer " + bearerToken);
                request.Method                 = "GET";
                request.ContentType            = "application/x-www-form-urlencoded;charset=UTF-8";
                request.AutomaticDecompression = DecompressionMethods.GZip;

                WebResponse response = await request.GetResponseAsync();

                string responseData = await new StreamReader(response.GetResponseStream()).ReadToEndAsync();

                var fromJsonArray = JsonConvert.DeserializeObject <IEnumerable <TwitterJson> >(responseData);

                string[] hashtagFilter = null;
                if (!string.IsNullOrEmpty(options.HashTagsFilter))
                {
                    hashtagFilter = options.HashTagsFilter.Split(',');
                }

                var tweets = from tweet in fromJsonArray
                             where
                             // Hashtags
                             (hashtagFilter == null || (hashtagFilter != null && hashtagFilter.Any(p => tweet.text.Contains(p))))
                             &&
                             // Show replies
                             (options.ShowReplies || String.IsNullOrEmpty(tweet.in_reply_to_screen_name))
                             select new TweetStruct()
                {
                    Message   = tweet.text,
                    Username  = tweet.user.screen_name,
                    Avatar    = tweet.user.profile_image_url,
                    Timestamp = (DateTime.ParseExact(tweet.created_at, "ddd MMM dd HH:mm:ss %zzzz yyyy", CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal)).ToFriendlyDate(),
                    Id        = tweet.id_str
                };

                tweetList.AddRange(tweets.Take(options.Count > 0 ? options.Count : 10));
            }

            result.Tweets           = tweetList;
            result.DateTimeExecuted = DateTime.Now;
            result.IsSuccessful     = true;
            result.Settings         = options;

            return(result);
        }
 public MultiTenantTwitterOptionsResolver(
     TwitterOptions originalOptions,
     ISiteResolver siteResolver,
     ISiteRepository siteRepository,
     MultiTenantOptions multiTenantOptions)
 {
     this.originalOptions    = originalOptions;
     this.siteResolver       = siteResolver;
     this.multiTenantOptions = multiTenantOptions;
     siteRepo = siteRepository;
 }
 public MultiTenantTwitterOptionsResolver(
     TwitterOptions originalOptions,
     ISiteSettings currentSite,
     MultiTenantOptions multiTenantOptions)
 {
     this.originalOptions = originalOptions;
     //this.siteResolver = siteResolver;
     site = currentSite;
     this.multiTenantOptions = multiTenantOptions;
     //siteRepo = siteRepository;
 }
Пример #15
0
        public static void CheckData(TwitterOptions options)
        {
            if (options.User == null)
            {
                throw new Exception("NO USER");
            }

            if (options.User.AppSettings == null)
            {
                throw new Exception("NO APPLICATION");
            }
        }
Пример #16
0
        public TwitterClient(
            IHttpClientFactory httpClientFactory,
            TwitterOptions twitterOptions)
        {
            _httpClient     = httpClientFactory.CreateClient();
            _twitterOptions = twitterOptions;

            _httpClient.BaseAddress = new Uri(twitterOptions.TwitterApiUrl);

            _sigHasher = new HMACSHA1(new ASCIIEncoding().GetBytes($"{_twitterOptions.ConsumerSecret}&{_twitterOptions.AccessTokenSecret}"));

            _httpClient.BaseAddress = new Uri(_twitterOptions.TwitterApiUrl);
        }
Пример #17
0
        void ConfigTwitterAuthentication(TwitterOptions options,
                                         Dictionary <string, string> claims)
        {
            var clientIdKey     = "Twitter:ClientId";
            var ClientSecretKey = "Twitter:ClientSecret";

            if (claims.ContainsKey(clientIdKey) &&
                claims.ContainsKey(ClientSecretKey))
            {
                options.ConsumerKey    = claims[clientIdKey];
                options.ConsumerSecret = claims[ClientSecretKey];
            }
        }
Пример #18
0
        public async Task AddAsync_should_add_twitter_handler()
        {
            var eventCalled = false;

            Task onTicketReceived(TicketReceivedContext context)
            {
                eventCalled = true;
                return(Task.CompletedTask);
            }

            var provider = CreateServiceProvider(options =>
            {
                options.AddTwitter(configure =>
                {
                    configure.Events.OnTicketReceived = onTicketReceived;
                });
            });

            var twittertOptions = new TwitterOptions
            {
                ConsumerKey    = "test",
                ConsumerSecret = "test"
            };

            var scheme     = Guid.NewGuid().ToString();
            var definition = new TSchemeDefinition
            {
                Scheme      = scheme,
                DisplayName = "test",
                HandlerType = typeof(TwitterHandler),
                Options     = twittertOptions
            };

            var sut = provider.GetRequiredService <AuthenticationSchemeProviderWrapper>();

            Assert.Contains(typeof(TwitterHandler), sut.GetManagedHandlerTypes());

            await sut.AddAsync(definition);

            var state = await VerifyAddedAsync <TwitterOptions>(scheme, provider);

            var httpContext = new Mock <HttpContext>().Object;

            state.options.Events.OnTicketReceived(new TicketReceivedContext(
                                                      httpContext,
                                                      state.scheme as AuthenticationScheme,
                                                      state.options as TwitterOptions,
                                                      new AuthenticationTicket(new ClaimsPrincipal(), "test")));

            Assert.True(eventCalled);
        }
Пример #19
0
        public WebhookHostedService(
            IApplicationLifetime applicationLifetime,
            IOptions <TwitterOptions> options,
            ILogger <WebhookHostedService> logger)
        {
            _logger               = logger;
            _options              = options.Value;
            _webhooksManager      = new WebhooksPremiumManager(_options);
            _subscriptionsManager = new SubscriptionsManager(_options);

            // Initialize logic after host has started, to ensure WebhookMiddleware
            // is available for webhook registration
            applicationLifetime.ApplicationStarted.Register(InitializeWebhookAsync);
        }
        public TenantMiddleware(
            RequestDelegate next,
            TenantService tenantService,
            IAuthenticationSchemeProvider oauthProvider,
            IMemoryCache memoryCache,
            IdentityServerOptions identityServerOptions,

            IOptionsMonitor <AmazonAuthenticationOptions> amazonOptions,
            IOptionsMonitor <FacebookOptions> facebookOptions,
            IOptionsMonitor <GitHubOptions> githubOptions,
            IOptionsMonitor <GitterAuthenticationOptions> gitterOptions,
            IOptionsMonitor <GoogleOptions> googleOptions,
            IOptionsMonitor <InstagramAuthenticationOptions> instagramOptions,
            IOptionsMonitor <LinkedInAuthenticationOptions> linkedinOptions,
            IOptionsMonitor <MicrosoftAccountOptions> microsoftOptions,
            IOptionsMonitor <PaypalAuthenticationOptions> paypalOptions,
            IOptionsMonitor <QQOptions> qqOptions,
            IOptionsMonitor <RedditAuthenticationOptions> redditOptions,
            IOptionsMonitor <SalesforceAuthenticationOptions> salesforceOptions,
            IOptionsMonitor <TwitterOptions> twitterOptions,
            IOptionsMonitor <VisualStudioAuthenticationOptions> visualstudioOptions,
            IOptionsMonitor <WeiboOptions> weiboOptions,
            IOptionsMonitor <WeixinOptions> weixinOptions,
            IOptionsMonitor <WordPressAuthenticationOptions> wordpressOptions
            )
        {
            _next                  = next;
            _tenantService         = tenantService;
            _oauthProvider         = oauthProvider;
            _memoryCache           = memoryCache;
            _identityServerOptions = identityServerOptions;

            _amazonOptions       = amazonOptions.CurrentValue;
            _facebookOptions     = facebookOptions.CurrentValue;
            _githubOptions       = githubOptions.CurrentValue;
            _gitterOptions       = gitterOptions.CurrentValue;
            _googleOptions       = googleOptions.CurrentValue;
            _instagramOptions    = instagramOptions.CurrentValue;
            _linkedinOptions     = linkedinOptions.CurrentValue;
            _microsoftOptions    = microsoftOptions.CurrentValue;
            _paypalOptions       = paypalOptions.CurrentValue;
            _qqOptions           = qqOptions.CurrentValue;
            _redditOptions       = redditOptions.CurrentValue;
            _salesforceOptions   = salesforceOptions.CurrentValue;
            _twitterOptions      = twitterOptions.CurrentValue;
            _visualstudioOptions = visualstudioOptions.CurrentValue;
            _weiboOptions        = weiboOptions.CurrentValue;
            _weixinOptions       = weixinOptions.CurrentValue;
            _wordpressOptions    = wordpressOptions.CurrentValue;
        }
        public RetrieveTweetsViewComponent(ITwitterService twitterService, ILogger <RetrieveTweetsViewComponent> logger, TwitterCache cache, IOptions <TwitterOptions> options = null)
        {
            TwitterService = twitterService;
            Log            = logger;
            Cache          = cache;

            if (options != null)
            {
                TwitterOptions = options.Value;
            }
            else
            {
                TwitterOptions = new TwitterOptions();
            }
        }
        /// <summary>
        /// Adds the <see cref="TwitterMiddleware"/> middleware to the specified <see cref="IApplicationBuilder"/>, which enables Twitter authentication capabilities.
        /// </summary>
        /// <param name="app">The <see cref="IApplicationBuilder"/> to add the middleware to.</param>
        /// <param name="configureOptions">An action delegate to configure the provided <see cref="TwitterOptions"/>.</param>
        /// <returns>A reference to this instance after the operation has completed.</returns>
        public static IApplicationBuilder UseTwitterAuthentication(this IApplicationBuilder app, Action <TwitterOptions> configureOptions = null)
        {
            if (app == null)
            {
                throw new ArgumentNullException(nameof(app));
            }

            var options = new TwitterOptions();

            if (configureOptions != null)
            {
                configureOptions(options);
            }
            return(app.UseTwitterAuthentication(options));
        }
Пример #23
0
        public TwitterCacheWrapperService(ITwitterService twitterService, ILogger logger, TwitterCache cache, TwitterOptions options = null)
        {
            TwitterService = twitterService;
            Log            = logger;
            _cache         = cache.Cache;

            if (options != null)
            {
                TwitterOptions = options;
            }
            else
            {
                TwitterOptions = new TwitterOptions();
            }
        }
        public TwitterWidgetController(ITwitterService twitterService, ILogger <TwitterWidgetController> logger, TwitterCache cache, IOptions <TwitterOptions> options = null)
        {
            TwitterService = twitterService;
            Log            = logger;
            Cache          = cache;

            if (options != null)
            {
                TwitterOptions = options.Value;
            }
            else
            {
                TwitterOptions = new TwitterOptions();
            }
        }
Пример #25
0
        public static IApplicationBuilder UseMultiTenantTwitterAuthentication(
            this IApplicationBuilder app,
            Action <TwitterOptions> configureOptions)
        {
            //https://github.com/aspnet/Security/blob/582f562bbb20fc76f37023086e2b2d861eb4d43d/src/Microsoft.AspNet.Authentication.Twitter/TwitterOptions.cs

            var options = new TwitterOptions();

            if (configureOptions != null)
            {
                configureOptions(options);
            }

            return(app.UseMiddleware <MultiTenantTwitterMiddleware>(options));
        }
Пример #26
0
        public void Configure(string name, TwitterOptions options)
        {
            if (!string.Equals(name, TwitterDefaults.AuthenticationScheme, StringComparison.Ordinal))
            {
                return;
            }

            if (!ValidSettings())
            {
                return;
            }

            options.ConsumerKey    = _platoTwitterOptions.ConsumerKey;
            options.ConsumerSecret = _platoTwitterOptions.ConsumerSecret;

            if (_platoTwitterOptions.CallbackPath.HasValue)
            {
                options.CallbackPath = _platoTwitterOptions.CallbackPath;
            }
        }
Пример #27
0
        internal static HttpRequestMessage GetRequest(HttpMethod method, string baseUrl, TwitterOptions options, bool callBack, bool imageUpload)
        {
            //OAuthAuthenticator.Current.OnAuthenticationNeeded();

            string url = baseUrl;

            if (method == HttpMethod.Get)
            {
                url = $"{baseUrl}?{options.GetUrlParameters()}";
                if (url.EndsWith("?"))
                {
                    url = url.Substring(0, url.Length - 1);
                }
            }

            string nonce     = GetNonce();
            string timestamp = GetTimestamp();

            Dictionary <string, string> parms = GetParms(nonce, timestamp, options, callBack, imageUpload);
            string signatureBase = SignatureBsseString(method.Method, baseUrl, parms);
            string signature     = OAuthAuthenticator.SignBaseString(signatureBase, options.User.OAuthTokenSecret, options.User.AppSettings.AppSecret);
            string authHeader    = OAuthAuthenticator.AuthorizationHeader(nonce, signature, timestamp, options.User.OAuthToken, callBack, string.Empty, options.User.AppSettings.AppKey);

            HttpRequestMessage reqMsg = new HttpRequestMessage(method, url);

            reqMsg.Headers.Add(Constants.HEADERS.AUTHORIZATION, authHeader);

            return(reqMsg);
        }
Пример #28
0
        // Configure is called after ConfigureServices is called.
        public async void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory, SampleDataGenerator sampleData, AllReadyContext context, IConfiguration configuration)
        {
            // Put first to avoid issues with OPTIONS when calling from Angular/Browser.
            app.UseCors("allReady");

            // todo: in RC update we can read from a logging.json config file
            loggerFactory.AddConsole((category, level) =>
            {
                if (category.StartsWith("Microsoft."))
                {
                    return(level >= LogLevel.Information);
                }
                return(true);
            });

            if (env.IsDevelopment())
            {
                // this will go to the VS output window
                loggerFactory.AddDebug((category, level) =>
                {
                    if (category.StartsWith("Microsoft."))
                    {
                        return(level >= LogLevel.Information);
                    }
                    return(true);
                });
            }

            // Add Application Insights to the request pipeline to track HTTP request telemetry data.
            app.UseApplicationInsightsRequestTelemetry();

            // Add the following to the request pipeline only in development environment.
            if (env.IsDevelopment())
            {
                app.UseBrowserLink();
                app.UseDeveloperExceptionPage();
                app.UseDatabaseErrorPage();
            }
            else if (env.IsStaging())
            {
                app.UseDeveloperExceptionPage();
                app.UseDatabaseErrorPage();
            }
            else
            {
                // Add Error handling middleware which catches all application specific errors and
                // sends the request to the following path or controller action.
                app.UseExceptionHandler("/Home/Error");
            }

            // Track data about exceptions from the application. Should be configured after all error handling middleware in the request pipeline.
            app.UseApplicationInsightsExceptionTelemetry();

            // Add static files to the request pipeline.
            app.UseStaticFiles();

            app.UseRequestLocalization();

            // Add cookie-based authentication to the request pipeline.
            app.UseIdentity();

            // Add token-based protection to the request inject pipeline
            app.UseTokenProtection(new TokenProtectedResourceOptions
            {
                Path       = "/api/request",
                PolicyName = "api-request-injest"
            });

            // Add authentication middleware to the request pipeline. You can configure options such as Id and Secret in the ConfigureServices method.
            // For more information see http://go.microsoft.com/fwlink/?LinkID=532715
            if (Configuration["Authentication:Facebook:AppId"] != null)
            {
                var options = new FacebookOptions
                {
                    AppId     = Configuration["Authentication:Facebook:AppId"],
                    AppSecret = Configuration["Authentication:Facebook:AppSecret"],
                    BackchannelHttpHandler  = new FacebookBackChannelHandler(),
                    UserInformationEndpoint = "https://graph.facebook.com/v2.5/me?fields=id,name,email,first_name,last_name"
                };
                options.Scope.Add("email");

                app.UseFacebookAuthentication(options);
            }

            if (Configuration["Authentication:MicrosoftAccount:ClientId"] != null)
            {
                var options = new MicrosoftAccountOptions
                {
                    ClientId     = Configuration["Authentication:MicrosoftAccount:ClientId"],
                    ClientSecret = Configuration["Authentication:MicrosoftAccount:ClientSecret"]
                };

                app.UseMicrosoftAccountAuthentication(options);
            }

            //http://www.bigbrainintelligence.com/Post/get-users-email-address-from-twitter-oauth-ap
            if (Configuration["Authentication:Twitter:ConsumerKey"] != null)
            {
                var options = new TwitterOptions
                {
                    ConsumerKey    = Configuration["Authentication:Twitter:ConsumerKey"],
                    ConsumerSecret = Configuration["Authentication:Twitter:ConsumerSecret"]
                };

                app.UseTwitterAuthentication(options);
            }

            if (Configuration["Authentication:Google:ClientId"] != null)
            {
                var options = new GoogleOptions
                {
                    ClientId     = Configuration["Authentication:Google:ClientId"],
                    ClientSecret = Configuration["Authentication:Google:ClientSecret"]
                };

                app.UseGoogleAuthentication(options);
            }

            //call Migrate here to force the creation of the AllReady database so Hangfire can create its schema under it
            if (!env.IsProduction())
            {
                context.Database.Migrate();
            }

            //Hangfire
            app.UseHangfireDashboard("/hangfire", new DashboardOptions {
                Authorization = new[] { new HangireDashboardAuthorizationFilter() }
            });
            app.UseHangfireServer();

            // Add MVC to the request pipeline.
            app.UseMvc(routes =>
            {
                routes.MapRoute(name: "areaRoute", template: "{area:exists}/{controller}/{action=Index}/{id?}");
                routes.MapRoute(name: "default", template: "{controller=Home}/{action=Index}/{id?}");
            });

            // Add sample data and test admin accounts if specified in Config.Json.
            // for production applications, this should either be set to false or deleted.
            if (Configuration["SampleData:InsertSampleData"] == "true")
            {
                sampleData.InsertTestData();
            }

            if (Configuration["SampleData:InsertTestUsers"] == "true")
            {
                await sampleData.CreateAdminUser();
            }
        }
Пример #29
0
 public DirectMessageSender(TwitterOptions context)
 {
     Options = context;
 }
Пример #30
0
        /// <summary>
        /// Returns a ready 'OAuth ..' prefixed header to set in any call to Twitter API.
        /// </summary>
        /// <param name="options">Twitter app auth context.</param>
        /// <param name="method">The Request Http method.</param>
        /// <param name="requestUrl">The Request uri along with any query parameter.</param>
        /// <returns></returns>
        public static string Build(TwitterOptions options, HttpMethod method, string requestUrl)
        {
            if (!Uri.TryCreate(requestUrl, UriKind.RelativeOrAbsolute, out var resourceUri))
            {
                throw new TwitterException("Invalid Resource Url format.");
            }

            if (options == null || !options.IsValid)
            {
                throw new TwitterException("Invalid Twitter options.");
            }

            const string oauthVersion         = "1.0";
            const string oauthSignatureMethod = "HMAC-SHA1";

            // It could be any random string..
            var oauthNonce = DateTime.Now.Ticks.ToString();

            var epochTimeStamp =
                (DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc)).TotalSeconds;

            var oauthTimestamp = Convert.ToInt64(epochTimeStamp).ToString();

            var signatureParams = new Dictionary <string, string>
            {
                { "oauth_consumer_key", options.ConsumerKey },
                { "oauth_nonce", oauthNonce },
                { "oauth_signature_method", oauthSignatureMethod },
                { "oauth_timestamp", oauthTimestamp },
                { "oauth_token", options.AccessToken },
                { "oauth_version", oauthVersion }
            };

            var qParams = resourceUri.GetParams();

            foreach (var qp in qParams)
            {
                signatureParams.Add(qp.Key, qp.Value);
            }

            var baseString = string.Join("&",
                                         signatureParams.OrderBy(kpv => kpv.Key).Select(kpv => $"{kpv.Key}={kpv.Value}"));

            var resourceUrl = requestUrl.Contains("?")
                ? requestUrl.Substring(0, requestUrl.IndexOf("?", StringComparison.Ordinal))
                : requestUrl;

            baseString = string.Concat(method.Method.ToUpper(), "&", Uri.EscapeDataString(resourceUrl), "&",
                                       Uri.EscapeDataString(baseString));

            var oauthSignatureKey = string.Concat(Uri.EscapeDataString(options.ConsumerSecret), "&",
                                                  Uri.EscapeDataString(options.AccessSecret));

            string oauthSignature;

            using (var hasher = new HMACSHA1(Encoding.ASCII.GetBytes(oauthSignatureKey)))
            {
                oauthSignature = Convert.ToBase64String(hasher.ComputeHash(Encoding.ASCII.GetBytes(baseString)));
            }

            const string headerFormat = "OAuth oauth_nonce=\"{0}\", oauth_signature_method=\"{1}\", " +
                                        "oauth_timestamp=\"{2}\", oauth_consumer_key=\"{3}\", " +
                                        "oauth_token=\"{4}\", oauth_signature=\"{5}\", " +
                                        "oauth_version=\"{6}\"";

            return(string.Format(headerFormat,
                                 Uri.EscapeDataString(oauthNonce),
                                 Uri.EscapeDataString(oauthSignatureMethod),
                                 Uri.EscapeDataString(oauthTimestamp),
                                 Uri.EscapeDataString(options.ConsumerKey),
                                 Uri.EscapeDataString(options.AccessToken),
                                 Uri.EscapeDataString(oauthSignature),
                                 Uri.EscapeDataString(oauthVersion)));
        }