Facebook Application building. How do I do a simple API call? - api

I have 4.5 years experience as a professional PHP developer, I have loads of experience with session handling, etc.
I am wanting to learn how to build Facebook applications. I have gone through the process of downloading the Facebook Developer application, I have used to it Create an App, I have set the canvas URL to where the app is hosted.
I can successfully "install" the app using a Facebook user account, and I can successfully access it. I have noted that when the app is loaded, a whole string of data gets passed to it, with parameter names like fb_sig_user and fb_sig_session_key. Currently, I am doing nothing with these parameters.
On the application end, obviously I am supposed to create a Facebook object by using my own APP ID key and SECRET key, which I have done.
But I can't seem to figure out how to start making API calls from my application back to Facebook.
How do I, at this point, just do something simple like get the person's name and display it to them?
Eg, how do I:
$first_name = $facebook->getUserFirstName();
.. do something like that?
I just want to do a simple test to ensure the API stuff is working.
Any help would be appreciated. Thanks.

The Facebook PHP SDK would probably be your first stop, with some example code as a close runner up.
Making API calls with the Facebook SDK set up alright is as easy as;
$me = $facebook->api('/me'); // Returns array containing data for currently logged in user depending on given permissions
or
$my_friends = $facebook->api('/me/friends'); // Returns array containing information on friends of currently logged in user
and even
$my_profile_img = $facebook->api('/me/picture'); // Returns a string containing URL to users profile picture.
Also, everything within the open graph has unique id's that you can plug in instead of me in /me.
For further and more in-depth description of the Open Graph, I suggest going to the official Graph API Overview page.
Quite easy and fun to work with once you get it set up - albeit a bit slow.
Update:
In order to get the Facebook cookie and set up a session from it I did:
$cookie = get_facebook_cookie($fbconfig['appid'], $fbconfig['secret']);
function get_facebook_cookie($app_id, $application_secret) {
$args = array();
parse_str(trim($_COOKIE['fbs_' . $app_id], '\\"'), $args);
ksort($args);
$payload = '';
foreach ($args as $key => $value) {
if ($key != 'sig') {
$payload .= $key . '=' . $value;
}
}
if (md5($payload . $application_secret) != $args['sig']) {
return null;
}
return $args;
}
if (isset($cookie)) {
$session = $facebook->getSession($cookie);
}
Then updated Facebook.php line 332 to be
public function getSession($passedCookie) {
and line 373 to be
$this->setSession($passedCookie, $write_cookie);
Lame hacking, but it worked for me at least

Related

How to check if user is logged in, in Shopware 6 Storefront Controller or Subscriber?

I am looking for the right way on how to check, if a user is logged in, in the Shopware 6 storefront. I am writing a plugin (not an app), and want to use this in Controllers and/or Subscribers.
Should I:
Use the Storefront API? (but how? which path?)
Use the default symfony way? (isGranted) - but with which Roles? Isn't the role handling different?
Use some built-in functionality like a special service that I can fetch by Dependeny Injection (but which one?)?
Solution:
Thanks to #Uwe Kleinmann, I found a solution, that works in a subscriber like this:
public static function getSubscribedEvents()
{
return [
ProductPageLoadedEvent::class => 'onProductPageLoaded'
];
}
public function onProductPageLoaded(ProductPageLoadedEvent $event): void
{
$saleschannelContext = $event->getSaleschannelContext();
$customer = $saleschannelContext->getCustomer();
if(NULL === $customer) {
$customer = 'not-logged-in';
}
$event->getPage()->addExtension(
'myextension', new ArrayStruct([
'test' => $customer
])
);
}
The SalesChannelContext has a $customer (accessible with getCustomer()) attribute. This context is usually injected into both Storefront controllers and subscribers for any Storefront events.
It is only set, if the current user is logged-in.
You may also use the _loginRequired and _loginRequiredAllowGuest flags in the #Route annotation of a storefront controller's method. This is handy if you only want to allow access for logged in customers as this will automatically redirect logged out users to the login page and back to the origin after they logged in.
/**
* #Route("/my/custom/page", name="frontend.custom.page", methods={"GET"}, defaults={"_loginRequired"=true, "_loginRequiredAllowGuest"=true})
*/

TypeError: Cannot read property 'users' of undefined error

I have written the code:
function getId(username) {
var infoUrl = "https://www.instagram.com/web/search/topsearch/?context=user&count=0&query=" + username
return parseInt(fetch(infoUrl)['users']);
}
function fetch(url) {
var ignoreError = {
"muteHttpExceptions": true
};
var source = UrlFetchApp.fetch(url, ignoreError).getContentText();
var data = console.log(source);
return data;
}
To get the userID of the username input.
The error corresponds to the line:
return parseInt(fetch(infoUrl)['users']);
I have tried differnt things but I cant get it to work. The url leads to a page looking like this:
{"users": [{"position": 0, "user": {"pk": "44173477683", "username": "mykindofrock", "full_n........
Where the numbers 44173477683 after the "pk": are what I am trying to get as an output.
I hope someone can help as I am very out of my depth, but I guess this is how we learn! :)
I was surprised that the endpoint you provided actually led to a JSON file. I would have thought that to access the Instagram API, you would need register a developer account with Facebook etc. Nevertheless, it does return a JSON by visiting in the browser. I suppose that it just shows the publicly available information on each user.
However, with Apps Script it seems like a different story. I visited:
https://www.instagram.com/web/search/topsearch/?context=user&count=0&query=user
In a browser and chose a random user id. Then I called it from Apps Script with UrlFetchApp:
function test(){
var username = "username7890543216"
var infoUrl = "https://www.instagram.com/web/search/topsearch/?context=user&count=0&query=" + username
var options = {
'muteHttpExceptions': true
}
var result = UrlFetchApp.fetch(infoUrl, options)
console.log(result.getResponseCode())
}
Which returns a 429 response. Which is a "Too Many Requests" response. So if I had to guess, I would say that all requests to this unauthenticated endpoint from Apps Script have been blocked. This is why when replacing the console.log(result.getResponseCode()) with console.log(result.getContentText()), you get a load of HTML (not JSON) part of it which says:
<title>
Page Not Found • Instagram
</title>
Though maybe its IP based. Try and run this code from your end, unless you get a response code of 200, it is likely that you simply can't access this information from Apps Script.
You are setting data to the return value of console.log(source) which is undefined. So no matter what the data is, you will get undefined.
Another thing to avoid is that fetch will not necessarily be hoisted because fetch is a built in function to make API calls.

User login with Smart Card for Windows UWP app

This seems like such a simple thing but I have been trying to figure this out for over a week now and cannot seem to figure it out. We are creating a Windows UWP app using WinJS and would like the user to login to the app with a PIV (smart card)/PIN combination. Essentially, when the app starts it will verify that there is a smart card inserted into the device and then prompt the user for the PIN. If the PIN is validated against the smart card the app will log the user in.
We do have Windows 7 applications that currently do this and I attempted to convert that code however it appears the APIs we used are not valid for Windows UWP apps. I did post the question about those APIs but did not receive any responses (https://stackoverflow.com/questions/43344679/x509certificate2ui-class-equivalent-with-windows-uwp-and-winjs). With Windows 7 we used the X509Certificate2UI (https://msdn.microsoft.com/en-us/library/system.security.cryptography.x509certificates.x509certificate2ui(v=vs.110).aspx ) class to select a certificate which prompted the user for the PIN.
After a lot of research, I believe (and could be wrong) with Windows UWP I need to use the smart card APIs (https://learn.microsoft.com/en-us/uwp/api/windows.devices.smartcards ). I have been reading the past couple of days and went through several Microsoft documents on smart cards like this one: https://learn.microsoft.com/en-us/windows/uwp/security/smart-cards but have not been able to find a way to validate a user entered PIN against the PIN on the smart card.
From the SmartCardProvisioning class (https://learn.microsoft.com/en-us/uwp/api/windows.devices.smartcards.smartcardprovisioning ) we are able to call the requestPinChangeAsync() method which prompts the user for the current PIN and the new PIN. I am looking for similar functionality except that it only asks for the current PIN and then returns a value that will let the app know if the PIN was correct.
I have also read through Microsoft’s Hello (https://learn.microsoft.com/en-us/windows/uwp/security/microsoft-passport ) API but did not see a way to use it with smart cards.
Can anyone point me in the right direction on how to use two-factor authentication in my app using a smart card/PIN combination. It seems like I have been in a Google bubble for the past several days going round and round and need help to get out.
Thanks
edit to explain why it is not a duplicate:
Not really a duplicate, both questions were asked by me and I mention the other post in the bod of the question. In the other post I was looking for an equivalent to the X509Certificate2UI class for Windows UWP with WinJS. With further research, I am thinking that might not be the correct way to go therefore with this post I am looking to see if anyone can point me in the right direction to doing two-factor authentication using a PIV (smart card) and the PIN associated with the card.
EDIT: Share code that works:
Here is the WinJS code that seems to work. Not sure is there is a better way or not:
if (certToUse != null) {
Windows.Security.Cryptography.Core.PersistedKeyProvider.openKeyPairFromCertificateAsync(certToUse, Windows.Security.Cryptography.Core.HashAlgorithmNames.sha256, Windows.Security.Cryptography.Core.CryptographicPadding.rsaPkcs1V15).then(function (keyPair) {
var buffer = 'data to sign'
var data = Windows.Security.Cryptography.CryptographicBuffer.convertStringToBinary(buffer, Windows.Security.Cryptography.BinaryStringEncoding.utf16BE)
Windows.Security.Cryptography.Core.CryptographicEngine.signAsync(keyPair, data).then(function (signed) {
var results = Windows.Security.Cryptography.Core.CryptographicEngine.verifySignature(keyPair, data, signed)
completeValidatePin = true
successCallback(true)
}, function (reason) {
completeValidatePin = true
errorCallback('User cancelled login')
})
}, function (reason) {
completeValidatePin = true
errorCallback('Error using certificate')
})
} else {
errorCallback('Certificate not found')
}
I'm currently investigating your question and trying to determine if there is a good solution.
I did write the following code which I thought should work:
IReadOnlyList<Certificate> Certs;
CertificateQuery CertQuery = new CertificateQuery();
CertQuery.HardwareOnly = true;
Certs = await CertificateStores.FindAllAsync(CertQuery);
string strEncrypt = "test";
IBuffer BufferToEncrypt = CryptographicBuffer.ConvertStringToBinary(strEncrypt, BinaryStringEncoding.Utf8);
foreach (Certificate Cert in Certs)
{
if (Cert.HasPrivateKey && ((Cert.KeyStorageProviderName == "Microsoft Base Smart Card Crypto Provider") || Cert.KeyStorageProviderName == "Microsoft Smart Card Key Storage Provider"))
{
CryptographicKey Key = null;
try
{
Key = await PersistedKeyProvider.OpenKeyPairFromCertificateAsync(Cert, HashAlgorithmNames.Sha1, CryptographicPadding.RsaPkcs1V15);
}
catch (Exception ex)
{
// Could not open Smart Card Key Pair
}
if (Key != null)
{
try
{
// Try to Sign with Cert Private key
IBuffer EncryptedBuffer = CryptographicEngine.Sign(Key, BufferToEncrypt);
}
catch (Exception ex)
{
// Could not sign
}
}
}
}
Unfortunately, OpenKeyPairFromCertificateAsync creates a provider with a silent context so CryptographicEngine.Sign is unable to display a PIN dialog. I will have to look into it a bit more.

Node.js client for wit.ai calls multiple custom actions

I'm trying to write an example app in wit.ai. I followed the quickstart app using node.js client that is shown at https://wit.ai/docs/quickstart.
The example shown there has only one custom action. But when I try to add a new story and a new action, I see that the context is being shared between the stories. This is causing wrong behaviour(a custom action from another story is being executed).
I cannot find any example with multiple custom actions and stories. Are there any node.js or python examples other than the ones from wit.ai websites?
You need to create a context for each session, and this is a quick example (from https://github.com/wit-ai/node-wit/blob/master/examples/messenger.js):
const findOrCreateSession = (fbid) => {
let sessionId;
// Let's see if we already have a session for the user fbid
Object.keys(sessions).forEach(k => {
if (sessions[k].fbid === fbid) {
// Yep, got it!
sessionId = k;
}
});
if (!sessionId) {
// No session found for user fbid, let's create a new one
sessionId = new Date().toISOString();
sessions[sessionId] = {
fbid: fbid,
context: { // New context per session id.
_fbid_: fbid
}
}; // set context, _fid_
}
return sessionId;
};
You can find a working example at https://github.com/hunkim/Wit-Facebook.
I suppose wit engine don't store context on their side.
You 'merge' function must merge entities in different ways, depending on your app logic.
But if you story is completed, you need to clear context for next stories.
I added a built-in function clear-context and call this function from wit as action.
Check out my example.
It's not an official api, but you can understand how wit http api works.

create_assignment function in moodle

I am working on integration of moodle with openerp.
Is there any function in moodle for create_assignment in moodle webservice. I found moodle_assign_get_assignment function in External service of moodle. But i wants create_assignmet function. Help me about this.
Using Moodle 2.8.x, have you tried assignment_add_instance?
I haven't yet but I use PHPStorm as an IDE and it hooks into all the Moodle API functions. So I just typed "assignment" and found that.
It is located in mod/assigment.lib.php line 36 and looks like this:
function assignment_add_instance($assignment, $mform = null) {
global $DB;
$assignment->timemodified = time();
$assignment->courseid = $assignment->course;
$returnid = $DB->insert_record("assignment", $assignment);
$assignment->id = $returnid;
return $returnid;
}
What I tend to do is I create an assignment on a test version of my Moodle, intercept the form before it submits and var dump the submitted form so you can see what you have to send into the function for it to work.
Good luck.
Of course, it may be:
function assign_add_instance(stdClass $data, mod_assign_mod_form $form = null) {
global $CFG;
require_once($CFG->dirroot . '/mod/assign/locallib.php');
$assignment = new assign(context_module::instance($data->coursemodule), null, null);
return $assignment->add_instance($data, true);
}
That you have to call instead - cant remember which one superseded the other...