i have some problems with a SLIM 3 login middleware.
In any route I try to go i receive this browser error: "ERR_TOO_MANY_REDIRECTS".
It seems to be that SLIM entered a loop and could not render the login page.
What can i do?
I have obviously done the print_r of the session variables and of course it is initially empty and is only populated after the correct login..
This is my index php:
<?
use Slim\Views\PhpRenderer;
session_start();
define( "BASE_URL", "/test/");
define("ROOT_PATH", $_SERVER["DOCUMENT_ROOT"] . "/test/");
require 'vendor/autoload.php';
require 'config/db.php';
require('functions/middleware.php');
use \Psr\Http\Message\ServerRequestInterface as Request;
use \Psr\Http\Message\ResponseInterface as Response;
use Illuminate\Database\Capsule\Manager as Capsule;
$capsule = new Capsule;
$capsule->addConnection([
'driver' => 'mysql',
'host' => DB_HOST,
'port' => DB_PORT,
'database' => DB_NAME,
'username' => DB_USER,
'password' => DB_PASSWORD,
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
]);
$capsule->bootEloquent();
$capsule->setAsGlobal();
$config['displayErrorDetails'] = true;
$config['addContentLengthHeader'] = false;
$config['determineRouteBeforeAppMiddleware'] = true;
$app = new \Slim\App(['settings' => $config]);
$container = $app->getContainer();
$container['renderer'] = new PhpRenderer("./templates");
$container['notFoundHandler'] = function ($container) {
return function ($request, $response) use ($container) {
return $container['renderer']->render($response, "/404.php");
};
};
// Apply the middleware to every request.
$app->add($loggedInMiddleware);
include 'routes.php';
$app->run();
And this is the middleware included file:
<?
// Check the user is logged in when necessary.
$loggedInMiddleware = function ($request, $response, $next) {
$route = $request->getAttribute('route');
$routeName = $route->getName();
$groups = $route->getGroups();
$methods = $route->getMethods();
$arguments = $route->getArguments();
# Define routes that user does not have to be logged in with. All other routes, the user
# needs to be logged in with.
$publicRoutesArray = array(
'login',
'logout'
);
if (!$_SESSION && !in_array($routeName, $publicRoutesArray)) {
// redirect the user to the login page and do not proceed.
$response = $response->withRedirect('/test/login');
} else {
if ($routeName == "login")
return $response->withRedirect('/test/dashboard');
// Proceed as normal...
$response = $next($request, $response);
}
return $response;
};
And these are GET and POST login routes:
$app->get('login', function ($request, $response, $args) {
return $this->renderer->render($response, "/login.php", $args);
})->setName('login');
$app->post('login', function ($request, $response, $args) {
$res = [];
if(!$_POST['username'] || !$_POST['password']) {
$res['error'] = "Inserisci i campi richiesti per il LogIn";
return $this->response->withJson($res);
}
$thisUser = \test\Model\users::select("users.*")
->where("username",$_POST['username'])
->where("password",MD5($_POST['password']))
->get();
if (!$thisUser[0]){
$res['error'] = "I dati inseriti non corrispondono a nessun utente";
return $this->response->withJson($res);
}
$_SESSION['user']['id'] = $thisUser[0]['id'];
$_SESSION['user']['username'] = $thisUser[0]['username'];
$_SESSION['user']['role'] = $thisUser[0]['role'];
$_SESSION['user']['name'] = $thisUser[0]['name'];
$_SESSION['user']['profileImg'] = "https://www.media-rdc.com/medias/32d9119760683046ad0c1e2d7e50e009/p_50x50/stsm144.jpg";
$res['success'] = true;
return $this->response->withJson($res);
});
And finally this is my .htaccess:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^ index.php [QSA,L]
Well I've tried many things; I'm not sure if it is the right answer, but it solves the problem (at least on my end):
I've modified your middelware to this:
<?php
function (\Slim\Http\Request $request, \Slim\Http\Response $response, $next) {
$route = $request->getAttribute('route');
if (empty($route)) {
throw new \Slim\Exception\NotFoundException($request, $response);
}
$routeName = $route->getName();
// Define routes that user does not have to be logged in with. All other routes, the user
// needs to be logged in with.
$publicRoutesArray = array(
'login',
'logout'
);
if ( empty($_SESSION['user']) && !in_array($routeName, $publicRoutesArray)) {
// redirect the user to the login page and do not proceed.
return $response->withRedirect('/test/login');
}
// Proceed as normal...
return $next($request, $response);
}
?>
Also it seems that you have to include the test in the defined routes to work (or filter them out in .htaccess)
<?php
$app->get('/test/login', function ($request, $response, $args) {
return $this->renderer->render($response, 'index.phtml', $args);
})->setName('login');
?>
I sincerely hope it helps
You have a session, because you start the session at the very start:
<?
use Slim\Views\PhpRenderer;
session_start();
...
Your middleware is just checking if there is a session, not whether you set the user session variable from the user logging in.
if (!$_SESSION && !in_array($routeName, $publicRoutesArray)) {
// redirect the user to the login page and do not proceed.
$response = $response->withRedirect('/test/login');
} else {
if ($routeName == "login")
return $response->withRedirect('/test/dashboard');
// Proceed as normal...
$response = $next($request, $response);
}
Thus the app will go into the else statement when they hit the login route (and aren't signed in), which will redirect them to the dashboard (pretty sure this is what is "wrong", as you want them to stay there to submit a form to login). When they hit the dashboard, that route is not part of the public routes so it redirects them back to the login page. Thus the cycle continues forever.
Perhaps change:
if (!$_SESSION && in_array($routeName, $publicRoutesArray) === FALSE) {
// redirect the user to the login page and do not proceed.
$response = $response->withRedirect('/test/login');
} else {
to...
if (!isset($_SESSION['user'] && in_array($routeName, $publicRoutesArray) === FALSE) {
// redirect the user to the login page and do not proceed.
$response = $response->withRedirect('/test/login');
} else {
Related
I know that I can access the javascript var userName everywhere in the extjs backend, cause its defined globally in the themes/Backend/ExtJs/backend/index/header.tpl, to get information about the logged in user. But is there a way to get userId or role of the user in some way (without ajax requests)?
//{block name="backend/order/view/list/list"}
//{$smarty.block.parent}
Ext.define('Shopware.apps.Test.view.List', {
/**
* Defines an override applied to a class.
* #string
*/
override: 'Shopware.apps.Order.view.list.List',
getToolbar: function() {
// get this
var me = this;
// get parent action column
var result = me.callParent( arguments );
console.log(userName);
},
});
//{/block}
{block name="backend/base/header/javascript" append}
<script type="text/javascript">
var currentTabState = 'active';
window.addEventListener('blur', function () {
currentTabState = 'inactive';
});
window.addEventListener('focus', function () {
currentTabState = 'active';
});
var userName = '{$user->name}',
maxParameterLength = '{$maxParameterLength}';
You need to make the user available as Smarty variable, so you can simply access the data from this object.
For this you can subscribe to the PostDispatch event of the order backend controller Enlight_Controller_Action_PostDispatchSecure_Backend_Order in a subscriber and then you use the same code as in the Shopware_Controllers_Backend_Index to add the $user variable.
//{block name="backend/order/view/list/list"}
//{$smarty.block.parent}
Ext.define('Shopware.apps.Test.view.List', {
/**
* Defines an override applied to a class.
* #string
*/
override: 'Shopware.apps.Order.view.list.List',
getToolbar: function() {
// get this
var me = this;
// get parent action column
var result = me.callParent( arguments );
var userId = '{$user->id}';
var roleId = '{$user->role->getId()}';
console.log(userName);
},
});
//{/block}
{$user->role} contains the Shopware\Models\User\Role model, so you can access all data from this object with the corresponding getters.
If you want to know, which data you have available, just make a debug output in the \Shopware_Controllers_Backend_Index::indexAction method, right after the call $identity = $auth->getIdentity();
echo '<pre>';
\Doctrine\Common\Util\Debug::dump($identity);
echo '</pre>';
exit();
So I'm making a discord bot with a website. There is a form on the website, it requires you to put your discord tag (user#0000). So what i want to do is when you submit it, it checks if submitted tag is a real user.
Couldn't find anything.
Thanks.
Edit: Here is the post code
const fs = require("fs")
module.exports = (req,res,client) => {
let db = require("./feedback.json")
let d = true
let user = client.users.cache.find(u => u.tag == req.body.user) // What i tried
if (user == undefined) {
d = false
} else {
db.forEach((e) => {
if (e.dcName == req.body.dcName) {
d = false
}
})
}
if (d == true) {
db.push(req.body)
}
fs.writeFile("./webserver/feedback.json", JSON.stringify(db), (err) => {
if (err) throw err
})
if (d == true) {
res.redirect("/feedback?msg=0")
} else {
res.redirect("/feedback?msg=1")
}
}
There's no way to check whether your specified user tag is real unless that user is in the bot cache. You might want to request they put a user ID (and then fetch with client.users.fetch, which will always give you the user object if the user ID is real).
I can't rewrite your code without more information, however, please look into client.users.fetch() so you can make sure that if your user uses the bot, the bot has the user cached.
I'm trying to code a Webserver in plain NodeJS with http. What i'm trying to do is when you have the url /add/ whatever is after the /add/ would be added to a array, and showen on / but its not saving the array, and resets it when i add something new. Can someone explain what i did wrong?
Sorry that my code is a bit messy.
Index.js:
const http = require('http');
const $conf = require('./config.json');
http.createServer((req, res) => {
let $list = [];
const url = req.url;
const $req = url.split('/');
const $req_q = url.split('?');
if (req.url == "/"){
res.write($list.toString());
} else if (req.url == `/add/${$req[2]}`){
$list.push($req[2])
console.log($list)
res.write(`ADDED ${$req[2]}`)
} else {
res.write('Error');
}
res.end();
}).listen($conf.port);
Config.json:
{
"port": 80
}
When i goto /add/hi
i get "ADDED hi".
Then go back to /
and get nothing.
A NodeJS webserver executes a route (e.g '/' or '/add') on-demand. That means that everything inside the function is executed from scratch on every request.
Therefore your $list variable gets initialized everytime you call a route and you can't see the result on the screen.
You can fix it by moving the variable to the global scope.
const http = require('http');
const $conf = require('./config.json');
let $list = []; // Now this value is persisted between requests
http.createServer((req, res) => {
const url = req.url;
const $req = url.split('/');
const $req_q = url.split('?');
if (req.url == "/"){
res.write($list.toString());
} else if (req.url == `/add/${$req[2]}`){
$list.push($req[2])
console.log($list)
res.write(`ADDED ${$req[2]}`)
} else {
res.write('Error');
}
res.end();
}).listen($conf.port);
The main reason is the $list array is initialized every time there is a new request. So, there can be two ways of doing this at the moment.
Create a variable outside this route scope so you can access the previous value. (this variable will be shared for every request/client)
Another and more efficient way is you can store the value more efficiently using node-json-db, as there might be thousands of request for which you might need to save this data and it won't be efficient at that time. You can use node-json-db.
Sample code:
import { JsonDB } from 'node-json-db';
import { Config } from 'node-json-db/dist/lib/JsonDBConfig'
// The first argument is the database filename. If no extension, '.json' is assumed and automatically added.
// The second argument is used to tell the DB to save after each push
// If you put false, you'll have to call the save() method.
// The third argument is to ask JsonDB to save the database in an human readable format. (default false)
// The last argument is the separator. By default it's slash (/)
var db = new JsonDB(new Config("myDataBase", true, false, '/'));
// Pushing the data into the database
// With the wanted DataPath
// By default the push will override the old value
db.push("/test1","super test");
// Get the data from the root
var data = db.getData("/");
// From a particular DataPath
var data = db.getData("/test1");
// If you try to get some data from a DataPath that doesn't exists
// You'll get an Error
try {
var data = db.getData("/test1/test/dont/work");
} catch(error) {
// The error will tell you where the DataPath stopped. In this case test1
// Since /test1/test does't exist.
console.error(error);
};
There are several other operations you can perform for that you should check its documentation.
I am trying to get the selected element to the sidebar pane in my chrome extension.
It's working fine if the page has no frames when the element is in the frame, it's not working.
As per the document I have to pass the frameURL, but how do I get the frame or Iframe URL?
Thank you.
Note: This issue is duplicate that was opened in 3 years ago, but still no solution there, so re-opening it again.
In devtools.js
chrome.devtools.panels.elements.createSidebarPane(name, (panel) => {
// listen for the elements changes
function updatePanel() {
chrome.devtools.inspectedWindow.eval("parseDOM($0)", {
frameURL: // how to pass dynamic
useContentScriptContext: true
}, (result, exceptipon) => {
if (result) {
console.log(result)
}
if (exceptipon) {
console.log(exceptipon)
}
});
}
chrome.devtools.panels.elements.onSelectionChanged.addListener(updatePanel);
});
I ran into this as well. I ended up needing to add a content_script on each page/iframe and a background page to help pass messages between devtools and content scripts.
The key bit is that in the devtools page, we should ask the content_scripts to send back what their current url is. For every content script that was registered, we can then call chrome.devtools.inspectedWindow.eval("setSelectedElement($0)", { useContentScriptContext: true, frameURL: msg.iframe } );
Or in full:
chrome.devtools.panels.elements.createSidebarPane( "example", function( sidebar ) {
const port = chrome.extension.connect({ name: "example-name" });
// announce to content scripts that they should message back with their frame urls
port.postMessage( 'SIDEBAR_INIT' );
port.onMessage.addListener(function ( msg) {
if ( msg.iframe ) {
// register with the correct frame url
chrome.devtools.panels.elements.onSelectionChanged.addListener(
() => {
chrome.devtools.inspectedWindow.eval("setSelectedElement($0)", { useContentScriptContext: true, frameURL: msg.iframe } );
}
);
} else {
// otherwise assume other messages from content scripts should update the sidebar
sidebar.setObject( msg );
}
} );
}
);
Then in the content_script, we should only process the event if we notice that the last selected element ($0) is different, since each frame on the page will also handle this.
let lastElement;
function setSelectedElement( element ) {
// if the selected element is the same, let handlers in other iframe contexts handle it instead.
if ( element !== lastElement ) {
lastElement = element;
// Pass back the object we'd like to set on the sidebar
chrome.extension.sendMessage( nextSidebarObject( element ) );
}
}
There's a bit of setup, including manifest changes, so see this PR for a full example:
https://github.com/gwwar/z-context/pull/21
You can found url of the frame this way:
document.querySelectorAll('iframe')[0].src
Assuming there is at lease one iframe.
Please note, you cannot use useContentScriptContext: true, as it will make the script execute as a context page (per documentation) and it will be in a separate sandboxed environment.
I had a slightly different problem, but it might be helpful for your case too, I was dynamically inserting an iframe to a page, and then tried to eval a script in it. Here the code that worked:
let win = chrome.devtools.inspectedWindow
let code = `
(function () {
let doc = window.document
let insertFrm = doc.createElement('IFRAME')
insertFrm.src = 'about:runner'
body.appendChild(insertFrm)
})()`
win.eval(code, function (result, error) {
if (error) {
console.log('Eror in insertFrame(), result:', result)
console.error(error)
} else {
let code = `
(function () {
let doc = window.document
let sc = doc.createElement('script')
sc.src = '${chrome.runtime.getURL('views/index.js')}'
doc.head.appendChild(sc)
})()`
win.eval(code, { frameURL: 'about:bela-runner' }, function (result, error) {
if (error) {
console.log('Eror in insertFrame(), result:', result)
console.error(error)
}
})
}
})
I am trying to customise the name attribute for pageview events
This has previously been asked, for example How to provide custom names for page view events in Azure App Insights?
but this and all other solutions I've found (and the Microsoft documentation too) are working with an old version of the javascript snippet, of the form
window.appInsights = appInsights;
// …
appInsights.trackPageView();
The current snippet from the portal is very different though
var sdkInstance="appInsightsSDK";window[sdkInstance]="appInsights";var // ...
{
instrumentationKey:"key"
}); window[aiName] = aisdk,aisdk.queue && aisdk.queue.length ===0 && aisdk.trackPageView({});
I've tried this sort of thing
var sdkInstance="appInsightsSDK";window[sdkInstance]="appInsights";var aiName=window[sdkInstance],aisdk=window[aiName]||function(e){function n(e){t[e]=function(){var n=arguments;t.queue.push(function(){t[e].apply(t,n)})}}var t={config:e};t.initialize=!0;var i=document,a=window;setTimeout(function(){var n=i.createElement("script");n.src=e.url||"https://az416426.vo.msecnd.net/scripts/b/ai.2.min.js",i.getElementsByTagName("script")[0].parentNode.appendChild(n)});try{t.cookie=i.cookie}catch(e){}t.queue=[],t.version=2;for(var r=["Event","PageView","Exception","Trace","DependencyData","Metric","PageViewPerformance"];r.length;)n("track"+r.pop());n("startTrackPage"),n("stopTrackPage");var s="Track"+r[0];if(n("start"+s),n("stop"+s),n("setAuthenticatedUserContext"),n("clearAuthenticatedUserContext"),n("flush"),!(!0===e.disableExceptionTracking||e.extensionConfig&&e.extensionConfig.ApplicationInsightsAnalytics&&!0===e.extensionConfig.ApplicationInsightsAnalytics.disableExceptionTracking)){n("_"+(r="onerror"));var o=a[r];a[r]=function(e,n,i,a,s){var c=o&&o(e,n,i,a,s);return!0!==c&&t["_"+r]({message:e,url:n,lineNumber:i,columnNumber:a,error:s}),c},e.autoExceptionInstrumented=!0}return t}(
{
instrumentationKey:"my-key"
}); window[aiName] = aisdk;
if (aisdk.queue && 0 !== aisdk.queue.length) {
function adjustPageName(item) {
var name = item.name.replace("AppName", "");
if (name.indexOf("Order") !== -1)
return "Order";
if (name.indexOf("Product") !== -1)
return "Shop";
// And so on...
return name;
}
// Add telemetry initializer
aisdk.queue.push(function () {
aisdk.context.addTelemetryInitializer(function (envelope) {
var telemetryItem = envelope.data.baseData;
// To check the telemetry item’s type:
if (envelope.name === Microsoft.ApplicationInsights.Telemetry.PageView.envelopeType || envelope.name === Microsoft.ApplicationInsights.Telemetry.PageViewPerformance.envelopeType) {
// Do not track admin pages
if (telemetryItem.name.indexOf("Admin") !== -1)
return false;
telemetryItem.name = adjustPageName(telemetryItem);
}
});
});
aisdk.trackPageView();
};
But it doesn't work (no errors, but no effect on the telemetry either)
Has anyone managed to get anything like this working using the new snippet?
Please try the code below, I can add a custom property by using the latest javascript code snippet:
var sdkInstance="appInsightsSDK";window[sdkInstance]="appInsights";var aiName=window[sdkInstance],aisdk=window[aiName]||function(e){function n(e) { t[e] = function () { var n = arguments; t.queue.push(function () { t[e].apply(t, n) }) } }var t={config: e};t.initialize=!0;var i=document,a=window;setTimeout(function(){var n=i.createElement("script");n.src=e.url||"https://az416426.vo.msecnd.net/scripts/b/ai.2.min.js",i.getElementsByTagName("script")[0].parentNode.appendChild(n)});try{t.cookie = i.cookie}catch(e){}t.queue=[],t.version=2;for(var r=["Event","PageView","Exception","Trace","DependencyData","Metric","PageViewPerformance"];r.length;)n("track"+r.pop());n("startTrackPage"),n("stopTrackPage");var s="Track"+r[0];if(n("start"+s),n("stop"+s),n("setAuthenticatedUserContext"),n("clearAuthenticatedUserContext"),n("flush"),!(!0===e.disableExceptionTracking||e.extensionConfig&&e.extensionConfig.ApplicationInsightsAnalytics&&!0===e.extensionConfig.ApplicationInsightsAnalytics.disableExceptionTracking)){n("_" + (r = "onerror")); var o=a[r];a[r]=function(e,n,i,a,s){var c=o&&o(e,n,i,a,s);return!0!==c&&t["_"+r]({message: e,url:n,lineNumber:i,columnNumber:a,error:s}),c},e.autoExceptionInstrumented=!0}return t}(
{
instrumentationKey: "xxxxxxxxxx"
}
); window[aiName] = aisdk, aisdk.queue && 0 === aisdk.queue.length;
// Add telemetry initializer
aisdk.queue.push(function () {
var telemetryInitializer = (envelope) => {
//Add a custom property
envelope.data.name = 'This item passed through my telemetry initializer';
};
appInsights.addTelemetryInitializer(telemetryInitializer);
});
aisdk.trackPageView({})
Then in azure portal, the custom property is added: