Managing browser permissions with Laravel Dusk - javascript

Total Laravel Dusk noob here (started using it today). I wanted to test a "copy link" on the Web app I'm working on and I ran into browser permissions issues when trying to access the clipboard content while testing. Of course, that default behavior makes sense, because Google Chrome prompts the user and ask for permission to access the clipboard. However, I haven't found a way to tell Dusk to enable specific permissions. I found the following Cypress example that is probably the appropriate way of doing it, but I don't know if there's a Dusk equivalent.
cy.wrap(Cypress.automation('remote:debugger:protocol', {
command: 'Browser.grantPermissions',
params: {
permissions: ['clipboardReadWrite', 'clipboardSanitizedWrite'],
origin: window.location.origin,
},
}))
Thanks in advance!

You can add this function to your DuskTestCase class.
use Facebook\WebDriver\Chrome\ChromeDevToolsDriver;
//
protected function grantPermission(Browser $browser, $permissions)
{
try {
$driver = $browser->driver;
$devtools = new ChromeDevToolsDriver($driver);
$result = $devtools->execute('Browser.grantPermissions', [
"permissions" => $permissions,
]);
return $result;
} catch (\Exception) {
return null;
}
}
And use it globally in a real test case like this
public function testClipboard()
{
$this->browse(function (Browser $browser) {
$this->grantPermission($browser, ["clipboardReadWrite", "clipboardSanitizedWrite"]);
// Your test flow and assertion
});
}
Hope my answer can help.

Related

How can I use firebase without the emulator?

I am learning firebase and I checked this tutorial regards the authentication. (https://www.youtube.com/watch?v=rbuSx1yEgV8&t=502s). In this video, the emulator seems to be essential, however I want to communicate with the server. How do I do it? If I do not initialize the auth emulator ( by removing the connectEmulator() function) I just get the error 'auth/network-request-failed'.
const firebaseConfig = {
//...
};
const user = {
email: 'user#test.me',
password: 'test1234'
}
function func() {
createUserWithEmailAndPassword(auth, user.email, user.password)
.then((userCredential) => {
const user = userCredential.user;
console.log(user)
})
.catch((error) => {
console.log(error)
// ..
});
}
As you can see from the minute 7:37 of that video, I am getting his issue! So I assume I am following the wrong approach. Can someone help me? I would be really grateful.
You should be able to authenticate with the server.
The emulator is optional. Personally I rarely use it, and essentially always use the real online Firebase server. However there are many steps before you are able to authenticate with the server.
Step 1. Check you have copied the configuration correctly
Go to this link, but replace PROJECT_ID with your actual project Id:
https://console.firebase.google.com/u/0/project/PROJECT_ID/settings/general/
Check that you have correctly copied the value of this into your app code from that page. If you have not "added an app", you may need to click "Add app", to get this config to display.
const firebaseConfig = {
... blah blah ...
};
Step 2. Check that you have enabled a "Sign-in provider"
Go to this link (again PROJECT_ID should be replaced by your project Id):
https://console.firebase.google.com/u/0/project/PROJECT_ID/authentication/providers
At least one of the providers needs to be switched on, like so:
Step 3. Your code looks good.
I assume you have set up auth correctly - we can't see that in the snippet above.
Please paste into your question the exact error message you are seeing on the console, as text.
You might want to intensify the debugging as follows:
function func() {
console.log(`user: ${JSON.stringify(user,null,2)}`)
createUserWithEmailAndPassword(auth, user.email, user.password)
.then((userCredential) => {
console.log(`userCredential.user: ${JSON.stringify(userCredential.user,null,2)}`)
})
.catch((error) => {
console.error(error)
});
}
A small thing, but I suggest avoiding using the same variable name, user, for two different things. Javascript will keep them separate, but we as programmers sometimes will get muddled when looking back at the code.
Step 4. Make sure you have authorised the domain you are using.
Go to:
https://console.firebase.google.com/u/0/project/PROJECT_ID/authentication/settings
Make sure you have authorised the domain from which you are "calling" the Firebase server.
If your app is running on "127.0.0.1" instead of "localhost", you might need to add that IP address too. Or if you have deployed, the deployed domain.

Writing to Firestore Database Results in Firestore net::ERR_BLOCKED_BY_CLIENT Error

I am trying to write to my firestore database and I get a net::ERR_BLOCKED_BY_CLIENT. I have a user save info from a form and writing it to a database.
Here is the request:
// react app
const referenceDescriptionTextArea = useRef();
const proposalsCollectionReference = collection(db, "proposals");
const handleProposalSubmit = async (event) => {
event.preventDefault();
var data = {
author: getCurrentUser().uid,
timestamp: Timestamp.now(),
tokenid: tokenid,
type: "bio",
description: referenceDescriptionTextArea.current.value,
};
addDoc(proposalsCollectionReference, data).then(
(docRef) => {
console.log(docRef.id); //saf89hnasHJADH9
closeModal();
},
(err) => {
console.log(err);
}
);
};
Console Error after trying to submit a proposal:
channelrequest.js:1086 POST https://firestore.googleapis.com/google.firestore.v1.Firestore/Write/channel?VER=8&database=projects%2FREDACTED%2Fdatabases%2F(default)&gsessionid=sdaf7uOt-NfCFKX32b-Mw3sJBli_ssdsdfkaNw&SID=Q-mrJ98YFSsadflZRPA&RID=20557&TYPE=terminate&zx=pyjwqxvmw7j9 net::ERR_BLOCKED_BY_CLIENT
Some things I have tried are the following :
Double checked the firestore rules to make sure it is value. In this case I only want authenticated users to write to the doc like so. Error persists.
match /proposals/{proposal} {
allow read, write: if request.auth != null;
}
I was convinced this was a firestore rule so I changed the firestore rule to allow anyone to write to it (on my local deployment). Error persists.
match /proposals/{proposal} {
allow read, write: if true; // on local deployment but not working
}
Some users state this error is due to Adblockers. To check against this I opened up a new instance of Chrome without extensions but I get the same results. I tried other browsers and ran into similar issues. Error persists.
I found out it was Brave Shield on Brave. I did more research and heres what I gathered.
Edge, Chrome and Firefox: By default I use chrome. It is typical for other browsers like Edge and Firefox to prompt and auto import your settings (this includes bookmarks and extensions and only done once after install). Remove extensions like uBlockOrigin or HTTPS Everywehere. Once they were uninstalled I was able to make a request without an error
Brave Browser: By default it will have an adblocker called BraveShield. At the top right corner, click on the icon>Disable. The Error should now go away.

context.sendActivity(CardFactory.oauthCard(...)) seems much simpler, but doesn't work

I was hoping to write the authentication step myself instead of clone the samples repository so I can get a better understanding. Trying to keep it simple, I changed the onTurn function to:
public onTurn = async (context: TurnContext) => {
if (context.activity.type === ActivityTypes.Message) {
await context.sendActivity(CardFactory.oauthCard( ... );
}
};
But when I test it in the bot emulator, no oauth card shows up, nor any other response. But when I test the bot-authentication-msgraph sample in GitHub, it works fine. Can't I just use the one-line of code to authenticate users: context.sendActivity(CardFactory.oauthCard( ... )?
CardFactory.oauthCard will build a card as an attachment, but you still have to add it to an activity to send it out. This should do what you're looking for:
await context.sendActivity(MessageFactory.attachment(CardFactory.oauthCard(...)));

Google Sign In for Websites causing "Signature verification failed" with JWT PHP library

Google web sign in has driven me positively crazy...
I'm building a simple web application, and I'm trying to integrate Google's sign in feature into the website (https://developers.google.com/identity/sign-in/web/).
The JavaScript seemed to go fairly well, and the next step was to verify the id_token I was receiving with my backend server (again, against Google's recommendation: https://developers.google.com/identity/sign-in/web/backend-auth).
It's a PHP-based web application, and I've successfully installed the Google Client API library using composer: composer require google/apiclient, but when posting my id_token value to my PHP backend system I'm consistently receiving the following error:
Firebase\JWT\SignatureInvalidException
File: .\vendor\firebase\php-jwt\src\JWT.php:112
Message: Signature verification failed
Stack trace:
#0 .\vendor\google\apiclient\src\Google\AccessToken\Verify.php(103): Firebase\JWT\JWT::decode('eyJhbGciOiJSUzI...', '-----BEGIN PUBL...', Array)
#1 .\vendor\google\apiclient\src\Google\Client.php(712): Google_AccessToken_Verify->verifyIdToken('eyJhbGciOiJSUzI...', '10...')
I've also used the id_token value on Google's "tokeninfo" endpoint (https://www.googleapis.com/oauth2/v3/tokeninfo?id_token=ABC123), and the id_token validates perfectly, so I'm sure it's not the id_token value that's wrong. It's also passing it perfectly via the POST variable to the PHP script, so I'm at a bit of a loss.
Here's my code:
Javascript:
<script src="https://apis.google.com/js/platform.js?onload=googleAppStart" async defer></script>
<script>
var googleAppStart = function(){gapi.load('auth2', initGoogleSignIn);};
var auth = false;
function initGoogleSignIn(){
auth = gapi.auth2.init({
client_id : 'client-id-is-here',
scope : 'profile'
});
auth.attachClickHandler(document.getElementById('my-button'));
auth.isSignedIn.listen(googleSignInChanged);
auth.currentUser.listen(googleCurrentUserChanged);
if (auth.isSignedIn.get() == true)
auth.signIn();
}
function googleSignInChanged(signed_in){}
function googleCurrentUserChanged(user){
var auth_response = user.getAuthResponse();
var id_token = auth_response.id_token;
if (id_token != undefined){
var url = '/verify-google-signin';
var params = {id_token: id_token};
jQuery.post(url, params, function(data){}, 'json');
}
}
</script>
...and my PHP catching the POST:
<?php
require_once '/vendor/autoload.php';
$credentials = array("client_id" => "client-id-is-here");
$client = new \Google_Client($credentials);
$data = $_POST;
if (isset($data['id_token'])) {
$id_token = trim($data['id_token']);
// Exception generated here...
$payload = $client->verifyIdToken($id_token);
}
?>
Thank you so much for taking the time to read this, and for any assistance! It's greatly appreciated!
I had the same issue today.
Easier if you just execute:
composer require firebase/php-jwt:4.0
Fortunately you can verify id_token without google library as described here https://developers.google.com/identity/sign-in/web/backend-auth#calling-the-tokeninfo-endpoint
if (isset($data['id_token'])) {
$id_token = trim($data['id_token']);
try {
$res = (new \GuzzleHttp\Client())->request('GET',
'https://www.googleapis.com/oauth2/v3/tokeninfo', [
'query' => ['id_token' => $id_token],
]);
$payload = json_decode($res->getBody()->getContents(), true);
//you still need to check that the aud claim contains one of your app's client IDs
if ($payload['aud'] != "client-id-is-here") {
throw new \Exception("App Isn't valid", 422);
}
} catch (RequestException $e) {
//IF token isn't valid you will be here
if ($e->hasResponse()) {
/** #var \GuzzleHttp\Psr7\Response $resp */
$resp = $e->getResponse();
$error = json_decode($resp->getBody()->getContents(), true)['error_description'];
throw new \Exception($error, $resp->getStatusCode());
}
}
}
If you have no exceptions then your token is valid
It is a problem with php-jwt. Latest version is not working with Google Api Client.
Try to use php-jwt version 4.
I put "firebase/php-jwt": "<5.0" in my composer.json file.
Worked as a charm!
This has been fixed in v2.2.1 of google/apiclient so make sure you are running this version or later if anyone else encounters this issue.
Related discussions here and here.
I've got problems with Google Sign-In backend authentication yesterday, using both google/apiclient 2.2.0 and 2.1.3.
tl;dr it was most likely malfunctions on the Google side or some obscure limits I'm unaware of (nothing in the Developer Console about that).
First, the "idToken" Google was giving me client-side was not a valid JWT: openssl_verify() was rejecting it in Firebase\JWT\JWT, throwing a Firebase\JWT\SignatureInvalidException. I followed your advice, installed google/apiclient 2.1.3 and this exception was not being throwed anymore but the resulting payload was null (so the idToken was still invalid).
A few hours later, I had experienced intermittent results with the apiclient 2.3.0: sometimes the token was invalidated by signature verification (and throwing the signature exception) and sometimes the token was cryptographically valid but the returned payload was null. Once in a while, the token was valid (!).
In the end, the backend authenticaton process was succeeding every time.
As I began experiencing these problems, I tried to fix it generating new OAuth2 keys, revert to a previous verions of my codebase (both server-side and client-side) that I knew was working, removed all browser data and tried to get the token on Cordova with the Sign In for Android. Nothing worked. Also no message in the Developer Console, no visible limits, no security e-mail.
If it's not a bug but a feature, the error handling is quite harsh :)
If you are not using Firebase (taken from https://github.com/googleapis/google-api-php-client)
rm -r vendor/google/apiclient-services
Add this to composer.json
"scripts": {
"post-update-cmd": "Google\\Task\\Composer::cleanup"
},
"extra": {
"google/apiclient-services": [
"Drive" ,
"... any other services here ...",
]
}
Finally
composer install
This will resolve the error message with the added benefit of drastically reducing installed packages. As noted, there are at least 200 API services for GAPI

Firefox - Intercept/Modify post data when some variable match some pattern

I would like to know if it is possible to intercept and modify a post data when the url and some of the variables meet some pattern.
for example:
let the login url be: http://www.someonlineprofiles.com
let the post data be:
email: "myemail#gmail.com"
pass: "mypass"
theme: "skyblue"
I would like that if:
url = "http://www.someonlineprofiles.com/ajax/login_action_url" and
email = "myemail#gmail.com"
then theme value be unconditionally changed to: "hotdesert"
Is it possible to create a Firefox add-on for that?, are add-ons powerful enough for that?
I found this link:
modify the post data of a request in firefox extension
Thanks in advance!
[ADDED INFORMATION]
I don't know if it is interesting to know the version of my Firefox: 35.0.1
Your question borders on being too broad, so I will give only an overview on how to do this, but not a copy-paste-ready solution, which would take a while to create, and would also deny you a learning experience.
Observers
First of all, it is possible for add-ons to observe and manipulate HTTP(S) requests before the browser sends the request, you just need to implement and register what is called a http observer.
const {classes: Cc, instances: Ci, utils: Cu} = Components;
Cu.import("resource://gre/modules/Services.jsm"); // for Services
var httpRequestObserver = {
observe: function(channel, topic, data) {
if (topic != "http-on-modify-request") {
return;
}
if (!(channel instanceof Ci.nsIHttpChannel)) {
return; // Not actually a http channel
}
// See nsIChannel, nsIHttpChannel and nsIURI/nsIURL
if (channel.URI.host != "www.someonlineprofiles.com") {
return;
}
doSomething(channel);
},
register: function() {
Services.obs.addObserver(this, "http-on-modify-request", false);
},
unregister: function() {
Services.obs.removeObserver(this, "http-on-modify-request");
}
};
httpObserver.register();
// When your add-on is shut down, don't forget to call httpObserver.unregister();
Do only register the http observer once in your add-on:
If you're using the SDK, then put it into main.js or a dedicated module. You'll also need to rewrite the code a bit and replace the const .. = Components line with a require("chrome").
If you're writing a XUL overlay add-on, put it into a code module.
Rewriting post data
We still need to implement doSomething() and actually rewrite the post data. An http channel usually implements the nsIUploadStream interface, and the upload stream is where the current post data is, if any. It also has a setUploadStream() method, which you can use to replace the upload stream entirely.
function doSomething(channel) {
if (!(channel instanceof Ci.nsIUploadStream)) {
return;
}
// construct new post data
channel.setUploadStream(newStream);
}
Constructing the new post data would be a matter of your actual requirements. I provided a working example in another answer on how you could do it.
If you need to fetch some data from the old upload stream, you'll need to decode the existing channel.uploadStream as multipart/form-data yourself. I suggest you check TamperData and similar add-ons on how they do things there.

Categories