Fatal error: Uncaught OAuthException: (#100) - facebook-graph-api

I am getting a error
error_log: Could not set cookie. Headers already sent.
Fatal error: Uncaught OAuthException: (#100) link URL is not properly formatted thrown in /home/admin/facebook.php on line 453
The script worked a months ago so just uploaded it again and got a error. This is a custom built script so donno whats wrong so thought id ask here. Here is my code
require_once 'facebook.php';
require_once 'database.class.php';
require_once 'config.php';
/**
* FB Session
*/
$facebook = new Facebook(array(
'appId' => FB_APP_ID,
'secret' => FB_SECRET,
'cookie' => true,
));
$session = $facebook->getSession();
$params = array(
'canvas' => 1,
'fbconnect' => 0,
'next' => URL_CANVAS,
'req_perms' => 'publish_stream, offline_access'
);
$loginUrl = $facebook->getLoginUrl($params);
/**
* User authenticated?
*/
if ($session) {
try {
$fb_uid = $facebook->getUser();
$me = $facebook->api('/me');
$access_token = $session['access_token'];
$pg = 'main';
} catch (FacebookApiException $e) {
echo '<script type="text/javascript">top.location.href = "' . URL_CANVAS . '";</script>';
exit;
}
} else {
$pg = 'splash';
}
?>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:fb="http://www.facebook.com/2008/fbml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<meta http-Equiv="Cache-Control" Content="no-cache" />
<meta http-Equiv="Pragma" Content="no-cache" />
<meta http-Equiv="Expires" Content="0" />
<title>bloxorz worldst hardest game can you beat it ?</title>
<!--// using jQuery UI for this sample app //-->
<link href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8/themes/base/jquery-ui.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4/jquery.min.js"></script>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8/jquery-ui.min.js"></script>
<script type="text/javascript">
$(function() {
$("#tabs").tabs();
});
</script>
</head>
<body>
<!--// Facebook Javascript SDK needed for IFrame Canvas App //-->
<div id="fb-root"></div>
<script type="text/javascript" src="http://connect.facebook.net/en_US/all.js"></script>
<script type="text/javascript">
window.fbAsyncInit = function() {
FB.init({appId: '<?php echo FB_APP_ID; ?>', status: true, cookie: true, xfbml: true});
FB.Canvas.setSize();
};
(function() {
var e = document.createElement('script');
e.type = 'text/javascript';
e.src = document.location.protocol +
'http://connect.facebook.net/en_US/all.js';
e.async = true;
document.getElementById('fb-root').appendChild(e);
}());
</script>
<!--// START: page include //-->
<?php
if (!empty($pg)) {
include $pg . '.php';
} else {
echo '<b>Error:</b> Page Not Found.';
}
?>
<!--// END: page include //-->
or is the error in side the facebook.php page ?
Because the line 453 in facebook.php is
// results are returned, errors are thrown
if (is_array($result) && isset($result['error'])) {
$e = new FacebookApiException($result);
if ($e->getType() === 'OAuthException') {
$this->setSession(null);
}
throw $e;
}
return $result;
}

You have started "echoing" output before headers are being set. Facebook.php on line 453 is trying to set some response headers but it can't, because headers have already been set and body of response has started.
Make sure you don't echo, var_dump, pr or output anything to browser before line 453 is executed.

Related

How can I embed an Autodesk Forge Viewer to a Flask App without CORS errors?

I followed the Developer's Guide (step 1-3) to create an html file to view my BIM model - this worked fine.
But if I put the same code into a flask app I am not able to view the BIM model. I looked at the requests and found a couple of CORS errors while loading the document with Autodesk.Viewing.Document.load:
If I hover over CORS error I got a small popup telling me: "Cross origin resource sharing error: HeaderDisallowedByPreflightResponse".
I tried to change the callback url of my forge app to http://localhost:5001 and http://localhost:5001/* but this had no impact.
How can I embed an Autodesk Forge Viewer to a Flask App without CORS errors?
Why are there CORS errors on localhost but not on file:///.../index.html?
update:
Here is my html file - which works (I removed secrets here). I basically just put the same code into a flask app...
<!DOCTYPE html>
<html lang="en">
<head>
<meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1, user-scalable=no"/>
<meta charset="utf-8">
<title>Axpo BIM Viewer</title>
<link rel="stylesheet" href="https://developer.api.autodesk.com/modelderivative/v2/viewers/7.*/style.min.css"
type="text/css">
<script src="https://developer.api.autodesk.com/modelderivative/v2/viewers/7.*/viewer3D.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.js"></script>
<style>
body {
margin: 0;
}
#forgeViewer {
width: 100%;
height: 800px;
margin: 0;
background-color: #F0F8FF;
}
#forgeViewer > div {
height: 800px !important;
}
</style>
<script>
$(() => {
let client_id = '__client_id__'
let client_secret = '__client_secret__'
let documentId = 'urn:__documentId__'
let htmlDiv = document.getElementById('forgeViewer');
let viewer = new Autodesk.Viewing.GuiViewer3D(htmlDiv);
get_an_account(client_id, client_secret).then(function (response) {
initialize_viewer(viewer, response.access_token)
load_document(viewer, documentId)
});
});
async function get_an_account(client_id, client_secret) {
var request = {
"url": 'https://developer.api.autodesk.com/authentication/v1/authenticate',
"method": "POST",
"timeout": 0,
"headers": {
'Content-Type': 'application/x-www-form-urlencoded'
},
"data": {
client_id: client_id,
client_secret: client_secret,
grant_type: 'client_credentials',
scope: 'code:all data:write data:read bucket:create bucket:delete bucket:read'
}
};
return $.ajax(request);
}
function initialize_viewer(viewer, token) {
var options = {
env: 'AutodeskProduction2',
api: 'streamingV2', // for models uploaded to EMEA change this option to 'streamingV2_EU'
getAccessToken: function (onTokenReady) {
var timeInSeconds = 3600; // Use value provided by Forge Authentication (OAuth) API
onTokenReady(token, timeInSeconds);
}
};
Autodesk.Viewing.Initializer(options, () => {
var startedCode = viewer.start();
if (startedCode > 0) {
console.error('Failed to create a Viewer: WebGL not supported.');
return;
}
console.log('Initialization complete, loading a model next...');
});
}
function load_document(viewer, documentId) {
Autodesk.Viewing.Document.load(documentId, (viewerDocument) => {
var defaultModel = viewerDocument.getRoot().getDefaultGeometry();
viewer.loadDocumentNode(viewerDocument, defaultModel);
}, () => {
console.error('Failed fetching Forge manifest');
});
}
</script>
</head>
<body>
<div id="forgeViewer"></div>
</body>
</html>
I could not reproduce the issue, however, one thing that will be causing problems is that you're not waiting for initialize_viewer() to finish before trying to load a document. Looks like when using the file:// protocol, you don't run into problems with that though.
I turned that function into a Promise so that we can await it.
Also, it's better to keep the client secret on the server side, so I added that to the code too. You'll just have to update the variables in server.py
This solution worked fine for me. Maybe your Flask app has some different settings that cause the issue?
I had index.html in the templates folder:
<!DOCTYPE html>
<html lang="en">
<head>
<meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1, user-scalable=no" />
<meta charset="utf-8" />
<title>Axpo BIM Viewer</title>
<link rel="stylesheet" href="https://developer.api.autodesk.com/modelderivative/v2/viewers/7.*/style.min.css" type="text/css" />
<script src="https://developer.api.autodesk.com/modelderivative/v2/viewers/7.*/viewer3D.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<style>
body {
margin: 0;
}
#forgeViewer {
width: 100%;
height: 800px;
margin: 0;
background-color: #f0f8ff;
}
#forgeViewer>div {
height: 800px !important;
}
</style>
<script>
$(async() => {
let documentId = "urn:{{ documentId }}";
let htmlDiv = document.getElementById("forgeViewer");
let viewer = new Autodesk.Viewing.GuiViewer3D(htmlDiv);
await initialize_viewer(viewer);
load_document(viewer, documentId);
});
async function get_access_token(onTokenReady) {
var request = {
url: "/access_token",
method: "GET",
};
let res = await $.ajax(request);
console.log(res);
onTokenReady(res.access_token, res.expires_in);
}
async function initialize_viewer(viewer) {
return new Promise(resolve => {
var options = {
env: "AutodeskProduction2",
api: "streamingV2", // for models uploaded to EMEA change this option to 'streamingV2_EU'
getAccessToken: get_access_token,
};
Autodesk.Viewing.Initializer(options, () => {
var startedCode = viewer.start();
if (startedCode > 0) {
console.error("Failed to create a Viewer: WebGL not supported.");
return;
}
console.log("Initialization complete, loading a model next...");
resolve();
});
})
}
function load_document(viewer, documentId) {
console.log("Loading document");
Autodesk.Viewing.Document.load(
documentId,
(viewerDocument) => {
var defaultModel = viewerDocument.getRoot().getDefaultGeometry();
viewer.loadDocumentNode(viewerDocument, defaultModel);
},
() => {
console.error("Failed fetching Forge manifest");
}
);
}
</script>
</head>
<body>
<div id="forgeViewer"></div>
</body>
</html>
server.py
from flask import Flask, render_template
import requests
app = Flask(__name__)
# Update variable values
document_id=""
client_id=""
client_secret=""
#app.route("/")
def run():
return render_template('index.html', documentId=document_id)
#app.route("/access_token")
def get_access_token():
headers = {"Content-Type": "application/x-www-form-urlencoded"}
body = (
f"client_id={client_id}"
f"&client_secret={client_secret}"
"&grant_type=client_credentials"
"&scope=viewables:read"
)
print(body)
res = requests.post("https://developer.api.autodesk.com/authentication/v1/authenticate", data=body, headers=headers)
data = res.json()
return data
"Why are there CORS errors on localhost but not on file:///.../index.html?"
I guess the browser has different security concerns for the different protocols. The Viewer does not support the file:// protocol (only http:// / https://) and with some models you'll run into issues because of that - e.g. like this:

DJANGO PWA Install to home screen not working

I am trying to follow the instructions on this site (https://developer.mozilla.org/en-US/docs/Web/Progressive_web_apps/Add_to_home_screen) with my DJANGO app to make a PWA "Install to home screen' button.
I have SSL installed on the site, and it seems to me that the service worker is installed properly, I got the "Service Worker Registered" message back. However when I click the button nothing happens, the + sign does not appear in the URL bar as it should.
I have no idea what is causing the error, as there is no clear sign of anything not working properly.
My index.html:
{% load static %}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>A2HS demo</title>
<link href="{% static 'css/index.css' %}" rel="stylesheet">
<script src="{% static 'js/index.js' %}" defer></script>
<link rel="manifest" href="{% static 'manifest.json' %}">
</head>
<body>
<button class="add-button">Add to home screen</button>
</body>
</html>
My manifest.json:
{
"short_name": "Test site",
"name": "Test site",
"theme_color": "#062440",
"background_color": "#F7F8F9",
"display": "fullscreen",
"icons": [
{
"src": "assets/logo.png",
"type": "image/png",
"sizes": "192x192"
}
],
"start_url": "/index.html"
}
My index.js
// Register service worker to control making site work offline
if ('serviceWorker' in navigator) {
navigator.serviceWorker
.register('/static/js/service-worker.js')
.then(() => { console.log('Service Worker Registered'); });
}
// Code to handle install prompt on desktop
let deferredPrompt;
const addBtn = document.querySelector('.add-button');
addBtn.style.display = 'none';
window.addEventListener('beforeinstallprompt', (e) => {
// Prevent Chrome 67 and earlier from automatically showing the prompt
e.preventDefault();
// Stash the event so it can be triggered later.
deferredPrompt = e;
// Update UI to notify the user they can add to home screen
addBtn.style.display = 'block';
addBtn.addEventListener('click', () => {
// hide our user interface that shows our A2HS button
addBtn.style.display = 'none';
// Show the prompt
deferredPrompt.prompt();
// Wait for the user to respond to the prompt
deferredPrompt.userChoice.then((choiceResult) => {
if (choiceResult.outcome === 'accepted') {
console.log('User accepted the A2HS prompt');
} else {
console.log('User dismissed the A2HS prompt');
}
deferredPrompt = null;
});
});
});
And my service-worker.js:
self.addEventListener('install', (e) => {
e.waitUntil(
caches.open('fox-store').then((cache) => cache.addAll([
'/index.html',
'/static/css/index.css',
'/static/js/index.js',
])),
);
});
self.addEventListener('fetch', (e) => {
console.log(e.request.url);
e.respondWith(
caches.match(e.request).then((response) => response || fetch(e.request)),
);
});

Resource interpreted as Stylesheet but transferred with MIME type text/html: "http://localhost:4000/style.css"

I am using deno, oak and denjucks. The file structure is as below -
index.html
index.ts
style.css
the code I have used are as below -
index.ts is-
import {Application, send} from "https://deno.land/x/oak/mod.ts";
import denjucks from "https://deno.land/x/denjucks/mod.js";
const app = new Application();
const HOST = "http://localhost";
denjucks.configure('', { autoescape: true });
const PORT = 4000;
let res = denjucks.render("index.html", {txt: "World"});
app.use(async (context) => {
context.response.body = res;
});
console.log(`Server started at: ${HOST}:${PORT}`);
await app.listen({ port: PORT });
index.html -
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="./style.css" type="text/css">
<title>Document</title>
</head>
<body>
<h1>{{txt}}</h1>
<h1>Hello World</h1>
</body>
</html>
style.css -
body{
background: tomato;
}
when i execute code deno run --allow-all index.ts, in chrome developer tools console a warning message is coming - Resource interpreted as Stylesheet but transferred with MIME type text/html: "http://localhost:4000/style.css". and css code is not applying.
The reason behind this fault is not clear.
All your routes are serving text/html, since you're always responding with denjucks.render("index.html", {txt: "World"});, so when you request style.css you're' responding with index.html
You need to set up a static file middleware so ./style.css can be served correctly.
app.use(async (context) => {
await send(context, context.request.url.pathname, {
root: `${Deno.cwd()}`
});
});
app.use(async (context) => {
context.response.body = res;
});

Polymer not Defined in Web Component Tester

I am trying to run two tests with web-component-tester interactively on a Polymer 2 project in Chrome v69, web-component-test v 6.5.0, and webcomponentsjs v 2.1.3. The first super basic test passes, and the second fails with the following error:
Error: Polymer is not defined flush at shop-home.test.html:36
<html>
<head>
<meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes">
<title>shop-home</title>
<script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
<script>void(0)</script>
<script src="/bower_components/web-component-tester/browser.js"></script>
<link rel="import" href="/bower_components/test-fixture/test-fixture.html">
<link rel="import" href="../shop-home.html">
</head>
<body>
<test-fixture id="basic">
<template>
<shop-home></shop-home>
</template>
</test-fixture>
<script>
suite('shop-home tests', () => {
var home;
setup(() => {
home = fixture('basic');
});
test('super basic test', (done) => {
flush(() => {
console.log('what a great test')
done();
});
});
test('load mission statement', (done) => {
flush(() => {
let ms = Polymer.dom(home.root).querySelector('mission-statement');
assert.exists(ms, 'mission statement is neither `null` nor `undefined`');
done();
});
});
});
When running via the command line the error gives more detail:
Error: Error thrown outside of test function: document.getElementById(fixtureId).create is not a function. (In 'document.getElementById(fixtureId).create(model)', 'document.getElementById(fixtureId).create' is undefined)
at shop-home.html:25, 1 failed tests, Error thrown outside of test function: document.getElementById(...).create is not a function
at shop-home.html:25
How can I prevent this and run a proper unit test?

Testing asynchronously returned data

I have the following example:
<!DOCTYPE html>
<html>
<head>
<title>Mocha</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="mocha.css" />
</head>
<body>
<div id="mocha"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/mocha/3.1.2/mocha.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/chai/3.5.0/chai.min.js"></script>
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue-resource/1.0.3/vue-resource.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/sinon.js/1.15.4/sinon.js"></script>
<script>mocha.setup('bdd');</script>
<script>
"use strict";
var assert = chai.assert;
var should = chai.should();
var vm = new Vue({
data: {
message: "Hello"
},
methods: {
loadMessage: function() {
this.$http.get("/get").then(
function(value) {
this.message = value.body.message;
});
},
}
});
describe('getMessage', function() {
let server;
beforeEach(function () {
server = sinon.fakeServer.create();
});
it("should get the message", function(done) {
server.respondWith([200, { 'Content-Type': 'application/json' },
JSON.stringify({message: "Test"})]);
vm.message.should.equal("Hello");
vm.loadMessage();
server.respond();
setTimeout(function() {
// This one works, but it's quirky and a possible error is not well represented in the HTML output.
vm.message.should.equal("Test");
done();
}, 100);
// This one doesn't work
//vm.message.should.equal("Test");
});
});
</script>
<script>
mocha.run();
</script>
</body>
</html>
I want to test that Vue asynchronously gets data from the server. Though, I mock out the actual HTTP request with Sinon FakeServer.
Naturally, directly after the call to loadMessage, the message is not yet set. I could use a timeout function for the test, but I believe there should be a better method. I've looked into respondImmediately, but it did not change. Also, there is the possibility to call a done() function. However, as I understand this, this done would need to be called within the loadMessage function, hence modifying the code under test.
What is the correct approach to handle this problem?
Edit: I have found at least a partial solution, but it seems to be still messy: call the done() function in the mocha unit test. When the assertion fails, it is at least shown in the HTML output. However, the assertion message is not as clear as in a normal test. Also, the technique still seems messy to me.
Since updating of vue component is done asynchronously you would need to use
// Inspect the generated HTML after a state update
it('updates the rendered message when vm.message updates', done => {
const vm = new Vue(MyComponent).$mount()
vm.message = 'foo'
// wait a "tick" after state change before asserting DOM updates
Vue.nextTick(() => {
expect(vm.$el.textContent).toBe('foo')
done()
})
})
Taken from official docs.