예제 #1
0
        internal protected virtual void ApiAsync(string path, IDictionary <string, object> parameters, HttpMethod httpMethod, object userToken)
        {
            var mergedParameters = FacebookUtils.Merge(null, parameters);

            if (!mergedParameters.ContainsKey("access_token") && !String.IsNullOrEmpty(AccessToken))
            {
                mergedParameters["access_token"] = AccessToken;
            }

            Uri    requestUrl;
            string contentType;

            byte[] postData = BuildRequestData(path, mergedParameters, httpMethod, out requestUrl, out contentType);

            var tempState = new WebClientStateContainer
            {
                UserState  = userToken,
                Method     = httpMethod,
                RequestUri = requestUrl
            };

            Action <string, Exception> callback =
                (json, ex) =>
            {
                byte[] result = null;

                if (ex == null)
                {
                    result = Encoding.UTF8.GetBytes(json);
                }

                if (httpMethod == HttpMethod.Get)
                {
                    DownloadDataCompleted(this, new DownloadDataCompletedEventArgsWrapper(ex, false, tempState, result));
                }
                else
                {
                    UploadDataCompleted(this, new UploadDataCompletedEventArgsWrapper(ex, false, tempState, result));
                }
            };

            var request = (HttpWebRequest)HttpWebRequest.Create(requestUrl);

            request.Method = FacebookUtils.ConvertToString(httpMethod); // Set the http method GET, POST, etc.

            if (httpMethod == HttpMethod.Post)
            {
                if (path == null && mergedParameters.ContainsKey("batch"))
                {
                    tempState.IsBatchRequest = true;
                }

                request.ContentType = contentType;
                request.BeginGetRequestStream((ar) => { RequestCallback(ar, postData, callback, tempState); }, request);
            }
            else
            {
                request.BeginGetResponse((ar) => { ResponseCallback(ar, callback, tempState); }, request);
            }
        }
예제 #2
0
        private byte[] BuildRequestData(string path, IDictionary <string, object> parameters, HttpMethod method, out Uri requestUrl, out string contentType)
        {
            parameters = parameters ?? new Dictionary <string, object>();

            path = FacebookUtils.ParseQueryParametersToDictionary(path, parameters);

            Uri baseUrl;

            if (parameters.ContainsKey("method"))
            {
                if (String.IsNullOrEmpty((string)parameters["method"]))
                {
                    throw new ArgumentException("You must specify a value for the method parameter.");
                }

                // Set the format to json
                parameters["format"] = "json-strings";
                baseUrl = GetApiUrl(parameters["method"].ToString());
            }
            else
            {
                if (!String.IsNullOrEmpty(path) && path.StartsWith("/", StringComparison.Ordinal))
                {
                    path = path.Substring(1, path.Length - 1);
                }
                baseUrl = GetUrl("graph", path);
            }

            return(BuildRequestData(baseUrl, parameters, method, out requestUrl, out contentType));
        }
예제 #3
0
        /// <summary>
        /// Parses the session value from a cookie.
        /// </summary>
        /// <param name="appSecret">
        /// The app Secret.
        /// </param>
        /// <param name="cookieValue">
        /// The session value.
        /// </param>
        /// <returns>
        /// The Facebook session object.
        /// </returns>
        internal static FacebookSession ParseCookieValue(string appSecret, string cookieValue)
        {
            Contract.Requires(!String.IsNullOrEmpty(appSecret));
            Contract.Requires(!String.IsNullOrEmpty(cookieValue));
            Contract.Requires(!cookieValue.Contains(","), "Session value must not contain a comma.");

            // var cookieValue = "\"access_token=124973200873702%7C2.OAaqICOCk_B4sZNv59q8Yg__.3600.1295118000-100001327642026%7Cvz4H9xjlRZPfg2quCv0XOM5g9_o&expires=1295118000&secret=lddpssZCuPoEtjcDFcWtoA__&session_key=2.OAaqICOCk_B4sZNv59q8Yg__.3600.1295118000-100001327642026&sig=1d95fa4b3dfa5b26c01c8ac8676d80b8&uid=100001327642026\"";
            // var result = FacebookSession.Parse("3b4a872617be2ae1932baa1d4d240272", cookieValue);

            // Parse the cookie
            var dictionary = new JsonObject();
            var parts      = cookieValue.Replace("\"", string.Empty).Split('&');

            foreach (var part in parts)
            {
                if (!string.IsNullOrEmpty(part) && part.Contains("="))
                {
                    var nameValue = part.Split('=');
                    if (nameValue.Length == 2)
                    {
                        var s = FacebookUtils.UrlDecode(nameValue[1]);
                        dictionary.Add(nameValue[0], s);
                    }
                }
            }

            var signature = GenerateSessionSignature(appSecret, dictionary);

            if (dictionary.ContainsKey("sig") && dictionary["sig"].ToString() == signature)
            {
                return(new FacebookSession(dictionary));
            }

            return(null);
        }
예제 #4
0
        /// <summary>
        /// Build the URL for given domain alias, path and parameters.
        /// </summary>
        /// <param name="name">
        /// The name of the domain (from the domain maps).
        /// </param>
        /// <param name="path">
        /// Optional path (without a leading slash)
        /// </param>
        /// <param name="parameters">
        /// Optional query parameters
        /// </param>
        /// <returns>
        /// The string of the url for the given parameters.
        /// </returns>
        internal virtual Uri GetUrl(string name, string path, IDictionary <string, object> parameters)
        {
            Contract.Requires(!String.IsNullOrEmpty(name));
            Contract.Ensures(Contract.Result <Uri>() != default(Uri));

            return(FacebookUtils.GetUrl(DomainMaps, name, path, parameters));
        }
예제 #5
0
        internal protected virtual object Api(string path, IDictionary <string, object> parameters, HttpMethod httpMethod, Type resultType)
        {
            var mergedParameters = FacebookUtils.Merge(null, parameters);

            if (!mergedParameters.ContainsKey("access_token") && !string.IsNullOrEmpty(AccessToken))
            {
                mergedParameters["access_token"] = AccessToken;
            }

            Uri    requestUrl;
            string contentType;

            byte[] postData = BuildRequestData(path, mergedParameters, httpMethod, out requestUrl, out contentType);

            var jsonString = MakeRequest(httpMethod, requestUrl, postData, contentType);

            var json = JsonSerializer.Current.DeserializeObject(jsonString);

            FacebookApiException facebookApiException =
                ExceptionFactory.GetGraphException(json) ??
                ExceptionFactory.CheckForRestException(DomainMaps, requestUrl, json);

            if (facebookApiException != null)
            {
                throw facebookApiException;
            }

            return(resultType == null ? json : JsonSerializer.Current.DeserializeObject(jsonString, resultType));
        }
        /// <summary>
        /// Gets the login uri.
        /// </summary>
        /// <param name="parameters">
        /// The parameters.
        /// </param>
        /// <returns>
        /// Returns the facebook login uri.
        /// </returns>
        /// <remarks>
        /// http://developers.facebook.com/docs/reference/dialogs/oauth
        /// Parameters that can be used:
        ///     client_id     : Your application's identifier. This is called client_id instead of app_id for this particular method to be compliant with the OAuth 2.0 specification. Required, but automatically specified by most SDKs.
        ///     redirect_uri  : The URL to redirect to after the user clicks a button on the dialog. Required, but automatically specified by most SDKs.
        ///     scope         : Optional. A comma-delimited list of permissions.
        ///     state         : Optional. An opaque string used to maintain application state between the request and callback. When Facebook redirects the user back to your redirect_uri, this value will be included unchanged in the response.
        ///     response_type : Optional, default is token. The requested response: an access token (token), an authorization code (code), or both (code_and_token).
        ///     display       : The display mode in which to render the dialog. The default is page on the www subdomain and wap on the m subdomain. This is automatically specified by most SDKs. (For WP7 builds it is set to touch.)
        /// </remarks>
        public Uri GetLoginUrl(IDictionary <string, object> parameters)
        {
            Contract.Ensures(Contract.Result <Uri>() != null);

            var defaultParameters = new Dictionary <string, object>();

            defaultParameters["client_id"]    = AppId;
            defaultParameters["redirect_uri"] = RedirectUri ?? new Uri("http://www.facebook.com/connect/login_success.html");
#if WINDOWS_PHONE
            defaultParameters["display"] = "touch";
#endif
            var mergedParameters = FacebookUtils.Merge(defaultParameters, parameters);

            // check if client_id and redirect_uri is not null or empty.
            if (mergedParameters["client_id"] == null || string.IsNullOrEmpty(mergedParameters["client_id"].ToString()))
            {
                throw new ArgumentException("client_id required.");
            }

            if (mergedParameters["redirect_uri"] == null || string.IsNullOrEmpty(mergedParameters["redirect_uri"].ToString()))
            {
                throw new ArgumentException("redirect_uri required.");
            }

            // seems like if we don't do this and rather pass the original uri object,
            // it seems to have http://localhost:80/csharpsamples instead of
            // http://localhost/csharpsamples
            // notice the port number, that shouldn't be there.
            // this seems to happen for iis hosted apps.
            mergedParameters["redirect_uri"] = mergedParameters["redirect_uri"].ToString();

            var url = "http://www.facebook.com/dialog/oauth/?" + FacebookUtils.ToJsonQueryString(mergedParameters);

            return(new Uri(url));
        }
예제 #7
0
        /// <summary>
        /// Generates a MD5 signature for the facebook session.
        /// </summary>
        /// <param name="secret">
        /// The app secret.
        /// </param>
        /// <param name="dictionary">
        /// The dictionary.
        /// </param>
        /// <returns>
        /// Returns the generated signature.
        /// </returns>
        /// <remarks>
        /// http://developers.facebook.com/docs/authentication/
        /// </remarks>
        internal static string GenerateSessionSignature(string secret, IDictionary <string, object> dictionary)
        {
            Contract.Requires(!string.IsNullOrEmpty(secret));
            Contract.Requires(dictionary != null);
            Contract.Ensures(!string.IsNullOrEmpty(Contract.Result <string>()));

            var payload = new StringBuilder();

            // sort by the key and remove "sig" if present
            var parts = (from a in dictionary
                         orderby a.Key
                         where a.Key != "sig"
                         select string.Format(CultureInfo.InvariantCulture, "{0}={1}", a.Key, a.Value)).ToList();

            parts.ForEach(s => payload.Append(s));
            payload.Append(secret);

            var hash = FacebookUtils.ComputerMd5Hash(Encoding.UTF8.GetBytes(payload.ToString()));

            var signature = new StringBuilder();

            foreach (var h in hash)
            {
                signature.Append(h.ToString("x2", CultureInfo.InvariantCulture));
            }

            return(signature.ToString());
        }
        /// <summary>
        /// Gets the logout url.
        /// </summary>
        /// <param name="parameters">
        /// The parameters.
        /// </param>
        /// <returns>
        /// Returns the logout url.
        /// </returns>
        public Uri GetLogoutUrl(IDictionary <string, object> parameters)
        {
            // more information on this at http://stackoverflow.com/questions/2764436/facebook-oauth-logout
            var uriBuilder = new UriBuilder("http://m.facebook.com/logout.php");

            var defaultParams = new Dictionary <string, object>();

            defaultParams["confirm"] = 1;
            defaultParams["next"]    = RedirectUri ?? new Uri("http://www.facebook.com");

            var mergedParameters = FacebookUtils.Merge(defaultParams, parameters);

            if (mergedParameters["next"] == null)
            {
                mergedParameters.Remove("next");
            }
            else
            {
                mergedParameters["next"] = mergedParameters["next"].ToString();
            }

            uriBuilder.Query = FacebookUtils.ToJsonQueryString(mergedParameters);

            return(uriBuilder.Uri);
        }
예제 #9
0
        /// <summary>
        /// Makes an asynchronous POST request to the Facebook server.
        /// </summary>
        /// <param name="path">
        /// The resource path.
        /// </param>
        /// <param name="parameters">
        /// The parameters.
        /// </param>
        /// <param name="callback">
        /// The callback.
        /// </param>
        public void PostAsync(string path, object parameters, FacebookAsyncCallback callback)
        {
            if (string.IsNullOrEmpty(path) && parameters == null)
            {
                throw new ArgumentException("At least path or parameters must be defined.");
            }

            PostAsync(path, FacebookUtils.ToDictionary(parameters), callback, null);
        }
예제 #10
0
        /// <summary>
        /// Makes an asynchronous POST request to the Facebook server.
        /// </summary>
        /// <param name="parameters">
        /// The parameters.
        /// </param>
        /// <param name="callback">
        /// The callback.
        /// </param>
        public void PostAsync(object parameters, FacebookAsyncCallback callback)
        {
            if (parameters == null)
            {
                throw new ArgumentNullException("parameters");
            }

            PostAsync(FacebookUtils.ToDictionary(parameters), callback, null);
        }
예제 #11
0
        /// <summary>
        /// Makes a POST request to the Facebook server.
        /// </summary>
        /// <param name="parameters">
        /// The parameters.
        /// </param>
        /// <exception cref="Facebook.FacebookApiException" />
        /// <returns>
        /// The json result.
        /// </returns>
        public object Post(object parameters)
        {
            Contract.Requires(parameters != null);
            if (parameters is IDictionary <string, object> )
            {
                return(Post((IDictionary <string, object>)parameters));
            }

            return(Post(FacebookUtils.ToDictionary(parameters)));
        }
예제 #12
0
        /// <summary>
        /// Makes a POST request to the Facebook server.
        /// </summary>
        /// <param name="path">
        /// The resource path.
        /// </param>
        /// <param name="parameters">
        /// The parameters.
        /// </param>
        /// <exception cref="Facebook.FacebookApiException" />
        /// <returns>
        /// The json result.
        /// </returns>
        public object Post(string path, object parameters)
        {
            Contract.Requires(!(String.IsNullOrEmpty(path) && parameters == null));

            if (parameters is IDictionary <string, object> )
            {
                return(Post(path, (IDictionary <string, object>)parameters));
            }

            return(Post(path, FacebookUtils.ToDictionary(parameters)));
        }
예제 #13
0
        public static FacebookApiException TryGetRestException(IDictionary <string, Uri> domainMaps, Uri requestUri, object json)
        {
            FacebookApiException error = null;

            // HACK: We have to do this because the REST Api doesn't return
            // the correct status codes when an error has occurred.
            if (FacebookUtils.IsUsingRestApi(domainMaps, requestUri))
            {
                // If we are using the REST API we need to check for an exception
                error = GetRestException(json);
            }

            return(error);
        }
예제 #14
0
        /// <summary>
        /// Internal method for parsing the Facebook oauth ur..
        /// </summary>
        /// <param name="uri">
        /// The url to parse.
        /// </param>
        /// <param name="throws">
        /// Whether to throw the exception or not incase an error occurs.
        /// </param>
        /// <returns>
        /// The <see cref="FacebookOAuthResult"/>.
        /// </returns>
        /// <exception cref="InvalidOperationException">
        /// Throws if cannot parse the specified url.
        /// </exception>
        private static FacebookOAuthResult Parse(Uri uri, bool throws)
        {
            IDictionary <string, object> parameters = null;

            try
            {
                bool found = false;
                if (!string.IsNullOrEmpty(uri.Fragment))
                {
                    // #access_token and expires_in are in fragment
                    var fragment = uri.Fragment.Substring(1);
                    parameters = FacebookUtils.ParseUrlQueryString(fragment);
                    if (parameters.ContainsKey("access_token"))
                    {
                        found = true;
                    }
                }

                // code, state, error_reason, error and error_description are in query
                // ?error_reason=user_denied&error=access_denied&error_description=The+user+denied+your+request.
                var queryPart = FacebookUtils.ParseUrlQueryString(uri.Query);
                if (queryPart.ContainsKey("code") || (queryPart.ContainsKey("error") && queryPart.ContainsKey("error_description")))
                {
                    found = true;
                }

                if (found)
                {
                    parameters = FacebookUtils.Merge(parameters, queryPart);
                    return(new FacebookOAuthResult(parameters));
                }
            }
            catch
            {
                if (throws)
                {
                    throw;
                }

                return(null);
            }

            if (throws)
            {
                throw new InvalidOperationException("Could not parse authentication url.");
            }

            return(null);
        }
예제 #15
0
        /// <summary>
        /// Builds the request post data and request uri based on the given parameters.
        /// </summary>
        /// <param name="uri">
        /// The request uri.
        /// </param>
        /// <param name="parameters">
        /// The request parameters.
        /// </param>
        /// <param name="httpMethod">
        /// The http method.
        /// </param>
        /// <param name="requestUrl">
        /// The outputted request uri.
        /// </param>
        /// <param name="contentType">
        /// The request content type.
        /// </param>
        /// <returns>
        /// The request post data.
        /// </returns>
        internal static byte[] BuildRequestData(Uri uri, IDictionary <string, object> parameters, HttpMethod httpMethod, out Uri requestUrl, out string contentType)
        {
            Contract.Requires(uri != null);
            Contract.Requires(parameters != null);

            var requestUrlBuilder = new UriBuilder(uri);

            // Set the default content type
            contentType = "application/x-www-form-urlencoded";
            byte[] postData    = null;
            string queryString = string.Empty;

            if (httpMethod == HttpMethod.Get)
            {
                queryString = FacebookUtils.ToJsonQueryString(parameters);
            }
            else
            {
                if (parameters.ContainsKey("access_token"))
                {
                    queryString = string.Concat("access_token=", parameters["access_token"]);
                    parameters.Remove("access_token");
                }
                else if (parameters.ContainsKey("oauth_token"))
                {
                    queryString = string.Concat("oauth_token=", parameters["oauth_token"]);
                    parameters.Remove("oauth_token");
                }

                var containsMediaObject = parameters.Where(p => p.Value is FacebookMediaObject).Count() > 0;
                if (containsMediaObject)
                {
                    string boundary = DateTime.Now.Ticks.ToString("x", CultureInfo.InvariantCulture);
                    postData    = BuildMediaObjectPostData(parameters, boundary);
                    contentType = String.Concat("multipart/form-data; boundary=", boundary);
                }
                else
                {
                    postData = Encoding.UTF8.GetBytes(FacebookUtils.ToJsonQueryString(parameters));
                }
            }

            requestUrlBuilder.Query = queryString;
            requestUrl = requestUrlBuilder.Uri;

            return(postData);
        }
예제 #16
0
        /// <summary>
        /// Checks for rest exception.
        /// </summary>
        /// <param name="domainMaps">
        /// The domain maps.
        /// </param>
        /// <param name="requestUri">
        /// The request uri.
        /// </param>
        /// <param name="json">
        /// The json string.
        /// </param>
        /// <returns>
        /// Returns <see cref="FacebookApiException"/> if it is a rest exception otherwise null.
        /// </returns>
        internal static FacebookApiException CheckForRestException(IDictionary <string, Uri> domainMaps, Uri requestUri, string json)
        {
            Contract.Requires(requestUri != null);

            FacebookApiException error = null;

            // HACK: We have to do this because the REST Api doesn't return
            // the correct status codes when an error has occurred.
            if (FacebookUtils.IsUsingRestApi(domainMaps, requestUri))
            {
                // If we are using the REST API we need to check for an exception
                var resultObject = JsonSerializer.Current.DeserializeObject(json);
                error = GetRestException(resultObject);
            }

            return(error);
        }
예제 #17
0
        public FacebookSession(IDictionary <string, object> dictionary, IFacebookApplication settings)
        {
            if (dictionary == null)
            {
                throw new ArgumentNullException("dictionary");
            }
            if (settings == null)
            {
                throw new ArgumentNullException("settings");
            }

            _settings = settings;
            var data = dictionary is JsonObject ? dictionary : FacebookUtils.ToDictionary(dictionary);

            AccessToken = data.ContainsKey("access_token") ? (string)data["access_token"] : null;

            if (!data.ContainsKey("uid") && !string.IsNullOrEmpty(AccessToken))
            {
                data.Add("uid", ParseUserIdFromAccessToken(AccessToken));
            }

            string sUserId = data.ContainsKey("uid") && data["uid"] != null ? data["uid"].ToString() : null;
            long   userId  = 0;

            long.TryParse(sUserId, out userId);
            UserId = userId;

            Secret     = data.ContainsKey("secret") ? (string)data["secret"] : null;
            SessionKey = data.ContainsKey("session_key") ? (string)data["session_key"] : null;

            if (data.ContainsKey("expires"))
            {
                Expires = data["expires"].ToString() == "0" ? DateTime.MaxValue : DateTimeConvertor.FromUnixTime(Convert.ToDouble(data["expires"]));
            }
            else
            {
                Expires = DateTime.MinValue;
            }

            Signature  = data.ContainsKey("sig") ? (string)data["sig"] : null;
            BaseDomain = data.ContainsKey("base_domain") ? (string)data["base_domain"] : null;

            _data = data;
        }
예제 #18
0
        private static string MakeRequest(HttpMethod httpMethod, Uri requestUrl, byte[] postData, string contentType)
        {
            var request = (HttpWebRequest)WebRequest.Create(requestUrl);

            request.Method = FacebookUtils.ConvertToString(httpMethod); // Set the http method GET, POST, etc.

            if (postData != null)
            {
                request.ContentLength = postData.Length;
                request.ContentType   = contentType;
                using (Stream dataStream = request.GetRequestStream())
                {
                    dataStream.Write(postData, 0, postData.Length);
                }
            }

            var       responseData = string.Empty;
            Exception exception    = null;

            try
            {
                var response = (HttpWebResponse)request.GetResponse();
                using (var streamReader = new StreamReader(response.GetResponseStream()))
                {
                    responseData = streamReader.ReadToEnd();
                }

                response.Close();
            }
            catch (WebException ex)
            {
                exception = (Exception)ExceptionFactory.GetGraphException(ex) ?? ex;
            }
            finally
            {
                if (exception != null)
                {
                    throw exception;
                }
            }

            return(responseData);
        }
        /// <summary>
        /// Gets the login url.
        /// </summary>
        /// <param name="parameters">
        /// The parameters.
        /// </param>
        /// <returns>
        /// Returns the Facebook login url.
        /// </returns>
        /// <remarks>
        /// http://developers.facebook.com/docs/reference/dialogs/oauth
        /// Parameters that can be used:
        ///     client_id     : Your application's identifier. This is called client_id instead of app_id for this particular method to be compliant with the OAuth 2.0 specification. Required, but automatically specified by most SDKs.
        ///     redirect_uri  : The URL to redirect to after the user clicks a button on the dialog. Required, but automatically specified by most SDKs.
        ///     scope         : Optional. A comma-delimited list of permissions.
        ///     state         : Optional. An opaque string used to maintain application state between the request and callback. When Facebook redirects the user back to your redirect_uri, this value will be included unchanged in the response.
        ///     response_type : Optional, default is token. The requested response: an access token (token), an authorization code (code), or both (code token).
        ///     display       : The display mode in which to render the dialog. The default is page on the www subdomain and wap on the m subdomain. This is automatically specified by most SDKs. (For WP7 builds it is set to touch.)
        /// </remarks>
        public virtual Uri GetLoginUrl(IDictionary <string, object> parameters)
        {
            var defaultParameters = new Dictionary <string, object>();

            defaultParameters["client_id"]    = AppId;
            defaultParameters["redirect_uri"] = RedirectUri ?? new Uri("http://www.facebook.com/connect/login_success.html");
#if WINDOWS_PHONE
            defaultParameters["display"] = "touch";
#endif
            var mergedParameters = FacebookUtils.Merge(defaultParameters, parameters);

            // check if client_id and redirect_uri is not null or empty.
            if (mergedParameters["client_id"] == null || string.IsNullOrEmpty(mergedParameters["client_id"].ToString()))
            {
                throw new ArgumentException("client_id required.");
            }

            if (mergedParameters["redirect_uri"] == null || string.IsNullOrEmpty(mergedParameters["redirect_uri"].ToString()))
            {
                throw new ArgumentException("redirect_uri required.");
            }

            // seems like if we don't do this and rather pass the original uri object,
            // it seems to have http://localhost:80/csharpsamples instead of
            // http://localhost/csharpsamples
            // notice the port number, that shouldn't be there.
            // this seems to happen for iis hosted apps.
            mergedParameters["redirect_uri"] = mergedParameters["redirect_uri"].ToString();

            var url = "http://www.facebook.com/dialog/oauth/?" + FacebookUtils.ToJsonQueryString(mergedParameters);

            // In order to be compliant with the OAuth spec Facebook have made changes to their auth APIs.
            // As part of this update, they will be deprecating 'code_and_token' and need developers
            // to use 'code%20token'. Everything is identical, just replace '_and_' with encoded
            // <space> '%20'.
            // url = url.Replace("response_type=code+token", "response_type=code%20token");

            return(new Uri(url));
        }
예제 #20
0
        /// <summary>
        /// Makes a POST request to the Facebook server.
        /// </summary>
        /// <param name="parameters">
        /// The parameters.
        /// </param>
        /// <exception cref="Facebook.FacebookApiException" />
        /// <returns>
        /// The json result.
        /// </returns>
        public object Post(object parameters)
        {
            Contract.Requires(parameters != null);

            return(Post(FacebookUtils.ToDictionary(parameters)));
        }
예제 #21
0
        /// <summary>
        /// Makes an asynchronous POST request to the Facebook server.
        /// </summary>
        /// <param name="path">
        /// The resource path.
        /// </param>
        /// <param name="parameters">
        /// The parameters.
        /// </param>
        /// <param name="userToken">
        /// The user token.
        /// </param>
        public void PostAsync(string path, object parameters, object userToken)
        {
            Contract.Requires(!(String.IsNullOrEmpty(path) && parameters == null));

            PostAsync(path, FacebookUtils.ToDictionary(parameters), userToken);
        }
예제 #22
0
        /// <summary>
        /// Makes an asynchronous POST request to the Facebook server.
        /// </summary>
        /// <param name="parameters">
        /// The parameters.
        /// </param>
        /// <param name="callback">
        /// The callback.
        /// </param>
        public void PostAsync(object parameters, FacebookAsyncCallback callback)
        {
            Contract.Requires(parameters != null);

            PostAsync(FacebookUtils.ToDictionary(parameters), callback, null);
        }
예제 #23
0
        /// <summary>
        /// Makes an asynchronous POST request to the Facebook server.
        /// </summary>
        /// <param name="path">
        /// The resource path.
        /// </param>
        /// <param name="parameters">
        /// The parameters.
        /// </param>
        /// <param name="callback">
        /// The callback.
        /// </param>
        public void PostAsync(string path, object parameters, FacebookAsyncCallback callback)
        {
            Contract.Requires(!(String.IsNullOrEmpty(path) && parameters == null));

            PostAsync(path, FacebookUtils.ToDictionary(parameters), callback, null);
        }
예제 #24
0
        /// <summary>
        /// Makes an asynchronous POST request to the Facebook server.
        /// </summary>
        /// <param name="parameters">
        /// The parameters.
        /// </param>
        public void PostAsync(object parameters)
        {
            Contract.Requires(parameters != null);

            PostAsync(FacebookUtils.ToDictionary(parameters));
        }
예제 #25
0
        /// <summary>
        /// Converts the facebook batch to POST parameters.
        /// </summary>
        /// <param name="batchParameter">
        /// The batch parameter.
        /// </param>
        /// <returns>
        /// The post parameters.
        /// </returns>
        protected IDictionary <string, object> ToParameters(FacebookBatchParameter batchParameter)
        {
            Contract.Requires(batchParameter != null);
            Contract.Ensures(Contract.Result <IDictionary <string, object> >() != null);

            IDictionary <string, object> returnResult = null;

            var defaultParameters = new Dictionary <string, object>();

            defaultParameters["method"] = FacebookUtils.ConvertToString(batchParameter.HttpMethod);

            IDictionary <string, object> parameters = null;

            if (batchParameter.Parameters == null)
            {
                parameters = new Dictionary <string, object>();
            }
            else
            {
                if (batchParameter.Parameters is IDictionary <string, object> )
                {
                    parameters = (IDictionary <string, object>)batchParameter.Parameters;
                }
                else
                {
                    parameters = FacebookUtils.ToDictionary(batchParameter.Parameters);
                }
            }

            var    path        = FacebookUtils.ParseQueryParametersToDictionary(batchParameter.Path, parameters);
            string queryString = string.Empty;

            if (batchParameter.HttpMethod == HttpMethod.Get)
            {
                queryString = FacebookUtils.ToJsonQueryString(parameters);
            }
            else
            {
                defaultParameters["body"] = FacebookUtils.ToJsonQueryString(parameters);
            }

            var relativeUrl = new StringBuilder(path);

            if (!string.IsNullOrEmpty(queryString))
            {
                relativeUrl.AppendFormat("?{0}", queryString);
            }

            defaultParameters["relative_url"] = relativeUrl.ToString();

            var data = batchParameter.Data;

            if (data == null)
            {
                returnResult = defaultParameters;
            }
            else
            {
                if (!(data is IDictionary <string, object>))
                {
                    data = FacebookUtils.ToDictionary(batchParameter.Data);
                }

                returnResult = FacebookUtils.Merge(defaultParameters, (IDictionary <string, object>)data);
            }

            return(returnResult);
        }
예제 #26
0
        /// <summary>
        /// Parse the signed request string.
        /// </summary>
        /// <param name="secret">
        /// The secret.
        /// </param>
        /// <param name="signedRequestValue">
        /// The signed request value.
        /// </param>
        /// <param name="maxAge">
        /// The max age.
        /// </param>
        /// <param name="currentTime">
        /// The current time.
        /// </param>
        /// <param name="throws">
        /// The throws.
        /// </param>
        /// <returns>
        /// The FacebookSignedRequest.
        /// </returns>
        internal static IDictionary <string, object> TryParse(string secret, string signedRequestValue, int maxAge, double currentTime, bool throws)
        {
            Contract.Requires(!String.IsNullOrEmpty(signedRequestValue));
            Contract.Requires(!String.IsNullOrEmpty(secret));
            Contract.Requires(maxAge >= 0);
            Contract.Requires(currentTime >= 0);
            Contract.Requires(signedRequestValue.Contains("."), Properties.Resources.InvalidSignedRequest);

            try
            {
                // NOTE: currentTime added to parameters to make it unit testable.
                string[] split = signedRequestValue.Split('.');
                if (split.Length != 2)
                {
                    // need to have exactly 2 parts
                    throw new InvalidOperationException(Properties.Resources.InvalidSignedRequest);
                }

                string encodedSignature = split[0];
                string encodedEnvelope  = split[1];

                if (string.IsNullOrEmpty(encodedSignature))
                {
                    throw new InvalidOperationException(Properties.Resources.InvalidSignedRequest);
                }

                if (string.IsNullOrEmpty(encodedEnvelope))
                {
                    throw new InvalidOperationException(Properties.Resources.InvalidSignedRequest);
                }

                var envelope = (IDictionary <string, object>)JsonSerializer.Current.DeserializeObject(Encoding.UTF8.GetString(FacebookUtils.Base64UrlDecode(encodedEnvelope)));

                string algorithm = (string)envelope["algorithm"];

                if (!algorithm.Equals("AES-256-CBC HMAC-SHA256") && !algorithm.Equals("HMAC-SHA256"))
                {
                    // TODO: test
                    throw new InvalidOperationException("Invalid signed request. (Unsupported algorithm)");
                }

                byte[] key    = Encoding.UTF8.GetBytes(secret);
                byte[] digest = FacebookUtils.ComputeHmacSha256Hash(Encoding.UTF8.GetBytes(encodedEnvelope), key);

                if (!digest.SequenceEqual(FacebookUtils.Base64UrlDecode(encodedSignature)))
                {
                    throw new InvalidOperationException(Facebook.Web.Properties.Resources.InvalidSignedRequestSignature);
                }

                IDictionary <string, object> result;

                if (algorithm.Equals("HMAC-SHA256"))
                {
                    // for requests that are signed, but not encrypted, we're done
                    result = envelope;
                }
                else
                {
                    result = new JsonObject();

                    result["algorithm"] = algorithm;

                    long issuedAt = (long)envelope["issued_at"];

                    if (issuedAt < currentTime)
                    {
                        throw new InvalidOperationException(Web.Properties.Resources.OldSignedRequest);
                    }

                    result["issued_at"] = issuedAt;

                    // otherwise, decrypt the payload
                    byte[] iv            = FacebookUtils.Base64UrlDecode((string)envelope["iv"]);
                    byte[] rawCipherText = FacebookUtils.Base64UrlDecode((string)envelope["payload"]);
                    var    plainText     = FacebookUtils.DecryptAes256CBCNoPadding(rawCipherText, key, iv);

                    var payload = (IDictionary <string, object>)JsonSerializer.Current.DeserializeObject(plainText);
                    result["payload"] = payload;
                }

                return(result);
            }
            catch
            {
                if (throws)
                {
                    throw;
                }

                return(null);
            }
        }