POST request has $_SERVER['REQUEST_METHOD'] = 'GET' in Yii2 codeception testing - testing

I'm trying to write some acceptance tests for yii2 application.
I my SiteController I have some action, which include the following piece of code:
if (!Yii::$app->request->isPost) {
throw new NotFoundHttpException('Unexpected GET method');
}
When I'm trying to test this action - it's always FAILED, because my POST requests don't passed this check Yii::$app->request->isPost . They always have $_SERVER['REQUEST_METHOD'] = 'GET' instead of POST.
I tried this variants:
$I->sendPOST($url, $options)
$I->sendAjaxPostRequest($url, $options)
Also I tried to make custom actions in Helper like this
public function makePOST($url, $params = []) {
$this->getModule('PhpBrowser')->_loadPage('POST', $url, $params);
}
And then call it from my test.
In all cases I'm getting GET request instead of POST...
Please help me to understand why it happens.

Maybe the reason is CSRF?
Yii2 documentation CSRF
Warning: Disabling CSRF will allow any site to send POST requests to your site. It is important to implement extra validation such as checking an IP address or a secret token in this case.

Related

Can't perform HTTP Post Action from Logic App to Asp.net Core Web API

I've built many Logic Apps. I've also integrated with the Logic App API. For some reason, a Post request to an Asp.net Core Web API won't work. It works in Postman, but I can't get Logic Apps to complete the request.
The request arrives at my Web API. I can step through it during a remote debug session. I'm using the [FromBody] decorator on the API method. All the string values in the object are null.
Logic App Headers
Accept = "application/json"
ContentType = "application/json"
ContentLength = "35"
Host = "****.centralus.logic.azure.com"
API method
[HttpPost]
[Route("CreateSomething")]
public async Task<IActionResult> CreateSomething([FromBody] MyObject object)
{
//Create something great
}
I think it might have something to do with the Headers. I noticed that the Postman request won't succeed unless I check the Host and Content-Length box in the Headers section. According to this article, Logic Apps ignores those Headers.
https://learn.microsoft.com/en-us/azure/connectors/connectors-native-http
I've built the HTTP Post Action using the API as well as configured it manually using the Logic App UI in Azure.
By the way, does anyone know the Expression that will automatically calculate the ContentLength?
UPDATE:
I finally figured this out. I had to do some Ninja coding crap to make this work. I'll post my solution tomorrow.
Does anyone know how to make this work? Thanks in advance!
When you use the Logic App API to programmatically create Logic Apps, you have to specify the Body class for when you do something like an HTTP Post. When the Body JSON displayed in the designer, it contained a single object with the objects properties. My API method could not handle this. The key was to simply post the properties in the JSON Body. To make matters worse, I'm doing two HTTP Posts in this particular Logic App. When I tried to add my object properties to the existing Body class, it caused my other HTTP Post to stop working. To overcome this, I had to create a Body2 class with the objects properties. I then had to use the following line of code to replace body2 with body before adding the JSON to the Logic App API call.
This did not work.
body = new Body()
{
object = new Object()
{
//Properties
}
}
This worked.
body2 = new Body2()
{
Type = 0,
Description = "#{items('For_each_2')?['day']?['description']}",
Locations = item.Locations,
Cold = "#{items('For_each_2')?['temperature']?['cold']?['value']}",
Hot = "#{items('For_each_2')?['temperature']?['hot']?['value']}",
Hide = 0
}
Notice I used Replace on body2.
var options = new JsonSerializerOptions { WriteIndented = true, IgnoreNullValues = true};
string jsonString = ReplaceFirst(JsonSerializer.Serialize(myApp, options), "schema", "$schema").Replace("_else", "else").Replace("_foreach", "foreach").Replace("body2", "body");

Prevent getting old updates from Telegram Bot API using a web hook

I'm writing a Telegram bot and I'm using the official bot API. I've got a webhook server that handles requests and sends a 200 OK response for every request.
Before the server stops, the webhook is detached so Telegram does not send updates anymore. However, whenever I turn the bot on and set the webhook URL again, Telegram starts flooding the webhook server with old updates.
Is there any way I can prevent this without requesting /getUpdates repeatedly until I reach the last update?
Here's a heavily simplified version of how my code looks like:
var http = require('http'),
unirest = require('unirest'),
token = '***';
// Attach the webhook
unirest.post('https://api.telegram.org/bot' + token + '/setWebhook')
.field('url', 'https://example.com/api/update')
.end();
process.on('exit', function() {
// Detach the webhook
unirest.post('https://api.telegram.org/bot' + token + '/setWebhook')
.field('url', '')
.end();
});
// Handle requests
var server = http.createServer(function(req, res) {
res.writeHead(200, { 'Content-Type': 'text/plain' })
res.end('Thanks!');
});
server.listen(80);
Thanks in advance.
The best way is to use update_id which is a specific number that increases on every new request (i.e. update). How to implement it?
First off, let's start with the following anonymous class (using PHP7):
$lastUpdateId = new class()
{
const FILE_PATH = "last-update-id.txt";
private $value = 1;
public function __construct()
{
$this->ensureFileExists();
$this->value = filesize(self::FILE_PATH) == 0
? 0 : (int)(file_get_contents(self::FILE_PATH));
}
public function set(int $lastUpdateId)
{
$this->ensureFileExists();
file_put_contents(self::FILE_PATH, $lastUpdateId);
$this->value = $lastUpdateId;
}
public function get(): int
{
return $this->value;
}
public function isNewRequest(int $updateId): bool
{
return $updateId > $this->value;
}
private function ensureFileExists()
{
if (!file_exists(self::FILE_PATH)) {
touch(self::FILE_PATH);
}
}
};
What the class does is clear: Handling the last update_id via a plain file.
Note: The class is tried to be as short as possible. It does not provide error-checking. Use your custom implementation (e.g. use SplFileObject instead of file_{get|put}_contents() functions) instead.
Now, there are two methods of getting updates: Long Polling xor WebHooks (check Telegram bot API for more details on each methods and all JSON properties). The above code (or similar) should be used in both cases.
Note: Currently, it is impossible to use both methods at the same time.
Long Polling Method (default)
This way, you send HTTPS requests to Telegram bot API, and you'd get updates as response in a JSON-formatted object. So, the following work can be done to get new updates (API, why using offset):
$botToken = "<token>";
$updates = json_decode(file_get_contents("https://api.telegram.org/bot{$botToken}/getUpdates?offset={$lastUpdateId->get()}"), true);
// Split updates from each other in $updates
// It is considered that one sample update is stored in $update
// See the section below
parseUpdate($update);
WebHook Method (preferred)
Requiring support for HTTPS POST method from your server, the best way of getting updates at-the-moment.
Initially, you must enable WebHooks for your bot, using the following request (more details):
https://api.telegram.org/bot<token>/setWebhook?url=<file>
Replace <token> with you bot token, and <file> with the address of your file which is going to accept new requests. Again, it must be HTTPS.
OK, the last step is creating your file at the specified URL:
// The update is sent
$update = $_POST;
// See the section below
parseUpdate($update);
From now, all requests and updates your bot will be directly sent to the file.
Implementation of parseUpdate()
Its implementation is totally up to you. However, to show how to use the class above in the implementation, this is a sample and short implementation for it:
function parseUpdate($update)
{
// Validate $update, first
// Actually, you should have a validation class for it
// Here, we suppose that: $update["update_id"] !== null
if ($lastUpdateId->isNewRequest($update["update_id"])) {
$lastUpdateId->set($update["update_id"]);
// New request, go on
} else {
// Old request (or possible file error)
// You may throw exceptions here
}
}
Enjoy!
Edit: Thanks to #Amir for suggesting editions made this answer more complete and useful.
When you server starts up you can record the timestamp and then use this to compare against incoming message date values. If the date is >= the timestamp when you started...the message is ok to be processed.
I am not sure if there is a way you can tell Telegram you are only interested in new updates, their retry mechanism is a feature so that messages aren't missed...even if your bot is offline.
In the webhook mode, Telegram servers send updates every minute until receives an OK response from the webhook program.
so I recommend these steps:
Check your webhook program that you specified its address as url parameter of the setWebhook method. Call its address in a browser. It does not produce an output to view, but clears that probably there is no error in your program.
Include a command that produces a '200 OK Status' header output in your program to assure that the program sends this header to the Telegram server.
I have the same issue, then I tried to reset the default webhook with
https://api.telegram.org/bot[mybotuniqueID]/setWebhook?url=
after that, i verified the current getUpdates query were the same old updates but I sent new requests through the telegram's bot chat
https://api.telegram.org/bot[mybotuniqueID]/getUpdates
when I set up my webhook again the webhook read the same old updates. Maybe the getUpdates method is not refreshing the JSON content.
NOTE:
in my case, it was working fine until I decided to change /set privacy bot settings from botfather

disable csrf for unprotect method post, put and delete in laravel 5

in laravel 4 not use csrf protect method (POST, PUT and DELETE) is default but in larave 5 use csrf to protect post, put and delete method from injection code is default is default. this protection is no problem for form but it have problem for build api rest.
so help me to show how to disable csrf unprotect method ( POST, PUT and DELETE) for build api rest in laravel 5. thanks
go to app->http->kernel
open kernel file:
protected $middleware = [
\Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode::class,
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
// \App\Http\Middleware\VerifyCsrfToken::class, // this is the csrf token, just disable using '//'
];
It is a method from here and I have tested that it should be okay.
In short, to disable csrf in particular pages, just change the app/Http/Middleware/VerifyCsrfToken.php to something like this:
public function handle($request, Closure $next)
{
//disable CSRF check on following routes
$skip = array(
'user/path/xys',
'user/profile',
'my/unprotected/route'
);
foreach ($skip as $key => $route) {
//skip csrf check on route
if($request->is($route)){
return parent::addCookieToResponse($request, $next($request));
}
}
return parent::handle($request, $next);
}
If your concern is just for /api/* routes, you can follow my answer here on Stack Overflow
HOpe this helps you to get clean and short code.

How to pass authorization code from JSP to Servlet

I am at my wits end, 7 hours and counting.
I am new to FB development and am having an issue of passing the authorization code from my JSP to my Servlet.
1.) I use the social plugin for login in my JSP as shown below
<fb:login-button>Login with Facebook</fb:login-button>
This logs the user in and allows them to grant my app access to their personal information
2.) Once login and authorization are successful, the user is forwarded to my servlet from the JSP via the code below
FB.Event.subscribe('auth.login', function (response) {
window.location = "testservlet";
});
3.) But when I attempt to get the authorization code (so that I can get the auth. token) in my Servlet, the "code" is empty, see the code I am using to retrieve below
String authCode = req.getParameter("code");
Can anyone tell me what I am doing wrong? I am sure that I am missing something so simple..or am trying to do more than is necessary, thanks in advance
I am not familiar with Facebook dev, but concerning servlets, window.location normally speaking will not take you to a servlet.
try using jquery's ajax function and pass a "code" parameter. Do something like :
$.ajax({
url: yourServletPath+"testservlet",
data:"code="+codevariable,
dataType: "whatever data type your servlet returns",
success: function(response)
{
// wtv code to be done
}
});

Grails how to post out to someone else's API

I am writing a Grails app, and I want the controller to hit some other API with a POST and then use the response to generate the page my user sees. I am not able to Google the right terms to find anything about posting to another page and receiving the response with Grails. Links to tutorials or answers like "Thats called..." would me much appreciated.
Seems like you are integrating with some sort of RESTful web service. There is REST client plugin, linked here.
Alternatively, its quite easy to do this without a plugin, linked here.
I highly recommend letting your controller just be a controller. Abstract your interface with this outside service into some class like OtherApiService or some sort of utility. Keep all the code that communicates with this outside service in one place; that way you can mock your integration component and make testing everywhere else easy. If you do this as a service, you have room to expand, say in the case you want to start storing some data from the API in your own app.
Anyway, cutting and posting from the linked documentation (the second link), the following shows how to send a GET to an API and how to set up handlers for success and failures, as well as dealing with request headers and query params -- this should have everything you need.
#Grab(group='org.codehaus.groovy.modules.http-builder', module='http-builder', version='0.5.0-RC2' )
import groovyx.net.http.*
import static groovyx.net.http.ContentType.*
import static groovyx.net.http.Method.*
def http = new HTTPBuilder( 'http://ajax.googleapis.com' )
// perform a GET request, expecting JSON response data
http.request( GET, JSON ) {
uri.path = '/ajax/services/search/web'
uri.query = [ v:'1.0', q: 'Calvin and Hobbes' ]
headers.'User-Agent' = 'Mozilla/5.0 Ubuntu/8.10 Firefox/3.0.4'
// response handler for a success response code:
response.success = { resp, json ->
println resp.statusLine
// parse the JSON response object:
json.responseData.results.each {
println " ${it.titleNoFormatting} : ${it.visibleUrl}"
}
}
// handler for any failure status code:
response.failure = { resp ->
println "Unexpected error: ${resp.statusLine.statusCode} : ${resp.statusLine.reasonPhrase}"
}
}
You might also want to check out this, for some nifty tricks. Is has an example with a POST method.