Safari 14.0.3 getUserMedia (WebRTC) permission prompt a second time after disallowed the first one - safari

i think having an unexpected getUserMedia behaviour in Safari and i would like to know if i miss something.
In Chrome/Firefox if i dont allow the first getUserMedia({audio: true, video: true}) prompt every next call to it will fail with the error: NotAllowedError: The request is not allowed by the user agent or the platform in the current context, possibly because the user denied permission. and this seems fine.
However in safari if i dont allow the first getUserMedia call the second one with the same constraints will prompt again, any other constraints will fail with the previous error.
I created a simple reproduction repository here that you can run on each browser to compare (you must refuse the first prompt in order to reproduce the bug).
Weirdly the same code works every time on jsfiddle only for safari and keep the same behaviour for other browser (due to the iframe where the code is running i guess)
Here a recording of me reproducing my issue to better understand.
GetUserMedia call order:
// 1: press "Not allow"
getUserMedia({ video: true, audio: true });
// 2: will prompt again (that's the bug) and press "Allow"
getUserMedia({ video: true, audio: true });
// 3: will fail (that's the expected behaviour)
getUserMedia({ video: true, audio: true });
// 3bis: will fail too (that's the expected behaviour)
getUserMedia({ video: {deviceId: {exact: 'aValidDeviceId' }}, audio: {deviceId: {exact: 'aValidDeviceId' }} });
Do i miss something or is this indeed a bug with safari ?
Best regards

There's nothing wrong in Safari here. A browser is a "user agent" in the eyes of specifications, which say:
This is intentionally vague about the details of the permission UI and how the UA infers user intent. UAs should be able to explore lots of UI within this framework.
There's no singular permission model on the web. This is a good thing.
If you find yourself writing code that relies on how one browser works in regards to permissions, stop and rethink.
Any code that relies on Safari responding with "NotAllowedError" in a predictable manner, is likely trying to socially engineer an outcome, perhaps to help users through what browser buttons to click to enable the access your site needs to operate correctly.
But browsers cannot distinguish your actions from those of a malicious website, and they need some slack to protect users.
Therefore, the correct way to react to a "NotAllowedError" is to assume it came from the user. In cases where it comes from the user agent, assume the agent is acting in the interest of its user.
If you suspect a user agent is mistaken, please file a bug on that particular user agent so it can improve.
Permissions are tricky.
The web is unique in allowing safe browsing of uncurated, even malicious sites.
The browser ("user agent") is the only trusted party deemed to be acting in the best interest of its user when it comes to permissions. Sites cannot be trusted to manage them.
But browsers differ quite a bit in how they manage their users' permissions. This includes how they react when a user has been bothered enough in their view. This is because the ideal tradeoff between convenience and privacy has not been found yet. Therefore, differentiation and innovation in this area is good, and it is too early to calcify it.
Disclaimer: Permissions are evolving
Browsers aren't perfect. Web developers bear the brunt of this imperfection and differentiation, and cannot be faulted for wishing things were simpler. After all, most of us work on non-malicious websites.
So perhaps there are times when socially engineering around some browser is warranted (after you've filed bugs on it). But on stackoverflow I think we first owe to give the "correct" answer, and preface everything else as workarounds.

It's not a bug exactly. It's expected behavior. Safari, unlike Chrome(ium) and Firefox, does not persist users' acceptance or rejection of permission to access media.
It asks again next time when the user says "yes" as well as when she says "no".
It would be nice if Safari's media stuff was predictable for developers accustomedto the other browsers, but that's not the way it is.

Related

Anchor.click using executeJs function not working in real iPhone safari browser

I have a question regarding executeJs function.
page.executeJs("$0.click();", downloadAnchor.getElement());
This line of code is not working in real iPhone Safari browser, though it works in mobile responsive mode from desktop safari. Appreciate your help on this
Browsers will be "suspicious" of anything starting a download that isn't a direct reaction to interaction by the user. This is done as a security precaution since starting to download files without the user's explicit consent can be dangerous in specific cases. Different browsers and configurations have different policies for exactly where to draw the line.
In your case, the download isn't started as a direct consequence of user interaction but instead as direct consequence of receiving a message from the server. This kind of pattern will simply not work reliably no matter what you do.
Instead, you need to design the interaction so that the download is directly triggered by the user. The easiest way of doing that is by having the user directly click on the actual download link. If you want to have some indirection, then you still need to make the action work directly in the browser without going through the server.

Verification Google OAuth2 concert scren with the apps for personal use only

I recently asked this question and user's #DalmTo and #Sergio NH they gave me an exhaustive answer for which I thank them very much.
Moving forward to question, we started publishing the application, and its verification was not required, since no scope was added (here it is a little unclear why the requests worked in an application with a test mode in which these scope were not added (google drive, google sheet and google ads)).
However, this time the application in the "In Production" mode began to give us an "Unverified app screen" (see Unverified app screen). We decided that we still need to add scope to the list, and, of course, that the scope list (their list is described above) requires verification by Google.
We started filling in the necessary fields, while studying the Google documentation at the same time, and came across the following information (see block Verification process -> What are the requirements for verification?):
Apps not applicable for verification
Apps for internal use only
(single domain use) Apps for personal use only Apps that are Gmail
SMTP plugins for WordPress Apps that are in development or
staging/testing
Apps for personal use only
And this is just our case: we have already received permission from Google Ads and are just generating simple reports that we want to integrate with Google Sheet. I.e., this is an elementary script that works within this account (however, we still need to request the first concert screen, even for this developer account) and cannot be distributed to any other accounts.
But when adding our scope, Google requires us to pass verification, forcing us to fill in the required fields, in the form of domains and their verification via the Search Console (we have already done this and this stage does not cause difficulties) and links to Youtube videos - where we must show how scope is used.
And just this stage is not clear. We do not allow other people's accounts to connect to this application, and the software does not have any interface, it is just a script that receives data from Google Ads and saves it to Google Sheet (creating a file via Google Drive). We have described all this in the scope usage description field. But the link to the Youtube video is require field, and we sincerely do not understand why (considering our case) we should record something, and most importantly, what exactly we should record in this case. If the documentation itself says that in our case we do not even need a verification.
Maybe we did not understand something and now we are doing it wrong? We will be glad to receive any tips from experts working with Google Cloud Console and apologize in advance for broken English.
We also apologize in advance to the StackOverflow community that we have to publish such elementary (which we are absolutely sure of from our side) questions here. We come here from Google Cloud Console - > Support - > Community support, and we must first try to publish posts in the Google Groups specified there, but they simply do not answer us, apparently considering our questions too elementary and not worthy of attention (however, these same questions in Google Groups are moderated) (for example, the previous question). And we are no longer able to contact any other support. Once again, we apologize for having to ask about this here.
It is true that if your app is a single use app then you do not need to be verified.
However if you don't get your app verified then there will be some restrictions.
you will see the unverified app screen
your refresh tokens will probably only be good for two weeks.
In the case of the YouTube api uploaded videos will be suck private.
If you can live with those points then you don't need to verify your app and you can continue as is.
If on the other hand you don't want to see the unverified app screen and you want a refresh token that will last longer then two weeks. You will need to verify your app. Yes, Even if your app is a console application running as a job some where you still show the consent screen. This is the YouTube video you will need to show Google. Show the consent screen popping up show the URL bar and then show your script running. You also need to set up the homepage and privacy policy screens. Yes i 100% agree with you that this is silly.
When you go though the process. Explain to google that this is a single use script running as a job some where.
Unfortunately when Google changed it so that Refresh tokens expire for unverified apps they pretty much tied the hands of all developers who are running such single user scripts. We now have to get our apps verified if we don't want to have to request a new refresh token every two weeks.
If your program needs to access the requested scopes of the Google account privacy, even though the user is yourself, you also need to provide a youtube video to demonstrate how you use this program. The auditor cannot guarantee whether you will make this program public.

Simplify location permission prompts in iOS 11

My app needs the 'always' location permission. Apple complicated location permission options if apps ask for 'always' directly, so I started asking for 'while using' and then 'always'. This gives the user a first dialog, for 'while using', with buttons of 'Don't Allow' and 'Allow', which is great. However, I'd like the next dialog to have these same buttons (assuming they allow 'while using'), and I was getting this before my upgrade to iOS 11 Beta 5 (I'm not sure - I might have skipped a couple betas).
With iOS 11 Beta 5, I see complicated button text (like 'While using the app' and 'Always' instead of 'Don't Allow'/'Allow') EVEN IF the 'while using' permission is already granted.
I want to give users the simpler options. I think users read these permission dialogs about as often as they read EULAs, and that if it's not a simple allow/don't allow, most will just pick a random option instead of reading, and my app won't have the permission it needs.
Is this possible with the latest iOS 11 Beta? And will it be possible in the final iOS 11? I thought this was what Apple was suggesting - here's some advice (from https://m.rover.io/wwdc-2017-update-significant-updates-to-location-permissions-coming-with-ios-11-41f96001f87f):
For those seeking always permission levels, Apple is now recommending a new permission flow which is essentially a two-phased approach. The first phase or initial onboarding, should only ask for ‘when in use’ permissions...
The dialog stays the same for iOS 11.
With requestWhenInUseAuthorization() iOS will present these options:
If the user allowed location access while in use and you later ask to always access location with requestAlwaysAuthorization(), iOS will present these options. You are already getting the benefit here that Don't Allow Any Access is not offered:
If you ask for requestAlwaysAuthorization() right away before asking for requestWhenInUseAuthorization(), iOS will present these options:
So solve your problem, it is advisable to not just request the iOS dialogs but prepare the user with your own pre-dialog. Only request the iOS dialogs when you are sure that the user will accept. This will lower the chances that a user denies access this time, but maybe would have allowed access in other circumstances. Once the user denies, you cannot request the iOS dialogs anymore.
On a general note:
I think users read these permission dialogs about as often as they
read EULAs
Frankly said, that should not be the fundamental assumption on which we develop app workflows and govern user privacy.
Tech companies and the public discourse are increasingly focusing on user privacy. Giving choices is clearly not enough, part of the job is educating users that granting their location 24/7 to some possibly unknown hobby developer or a company in a country with unknown data protection laws is not the same as clicking Yes on an EULA. Also legal changes require that sharing of such sensitive information as your live location cannot be hidden somewhere in an EULA but must be explicitly opted-in by the user.
Thankfully the efforts of companies like Apple ensure responsible access to user data for developers to build great features. This can only be done by giving the choice to the users through conspicuous prompts like the one you are referring to. Because the alternative could be no data sharing or higher hurdles by law.
Update March 2018
To emphasize on the point made above: The recent lack of trust in tech regarding data privacy (Facebook & Cambridge Analytica) confirmed how important is it to understand the responsibility that comes with personal data. The result will be more external regulation - and rightly so. The conclusion for designing data access permission workflows can only be to inform and educate users and to transparently disclose what data is used for what purpose and give an easy to access option to un-share / delete data.
Update May 2018
With the European Union's General Data Protection Regulation (GDPR) coming into effect, it also became mandatory that you need to communicate information about how you process personal data in a way that’s concise, transparent, intelligible, easily accessible and in clear and plain language.

Reliably detecting PhantomJS-based spam bots

Is there any way to consistently detect PhantomJS/CasperJS? I've been dealing with a spat of malicious spambots built with it and have been able to mostly block them based on certain behaviours, but I'm curious if there's a rock-solid way to know if CasperJS is in use, as dealing with constant adaptations gets slightly annoying.
I don't believe in using Captchas. They are a negative user experience and ReCaptcha has never worked to block spam on my MediaWiki installations. As our site has no user registrations (anonymous discussion board), we'd need to have a Captcha entry for every post. We get several thousand legitimate posts a day and a Captcha would see that number divebomb.
I very much share your take on CAPTCHA. I'll list what I have been able to detect so far, for my own detection script, with similar goals. It's only partial, as they are many more headless browsers.
Fairly safe to use exposed window properties to detect/assume those particular headless browser:
window._phantom (or window.callPhantom) //phantomjs
window.__phantomas //PhantomJS-based web perf metrics + monitoring tool
window.Buffer //nodejs
window.emit //couchjs
window.spawn //rhino
The above is gathered from jslint doc and testing with phantom js.
Browser automation drivers (used by BrowserStack or other web capture services for snapshot):
window.webdriver //selenium
window.domAutomation (or window.domAutomationController) //chromium based automation driver
The properties are not always exposed and I am looking into other more robust ways to detect such bots, which I'll probably release as full blown script when done. But that mainly answers your question.
Here is another fairly sound method to detect JS capable headless browsers more broadly:
if (window.outerWidth === 0 && window.outerHeight === 0){ //headless browser }
This should work well because the properties are 0 by default even if a virtual viewport size is set by headless browsers, and by default it can't report a size of a browser window that doesn't exist. In particular, Phantom JS doesn't support outerWith or outerHeight.
ADDENDUM: There is however a Chrome/Blink bug with outer/innerDimensions. Chromium does not report those dimensions when a page loads in a hidden tab, such as when restored from previous session. Safari doesn't seem to have that issue..
Update: Turns out iOS Safari 8+ has a bug with outerWidth & outerHeight at 0, and a Sailfish webview can too. So while it's a signal, it can't be used alone without being mindful of these bugs. Hence, warning: Please don't use this raw snippet unless you really know what you are doing.
PS: If you know of other headless browser properties not listed here, please share in comments.
There is no rock-solid way: PhantomJS, and Selenium, are just software being used to control browser software, instead of a user controlling it.
With PhantomJS 1.x, in particular, I believe there is some JavaScript you can use to crash the browser that exploits a bug in the version of WebKit being used (it is equivalent to Chrome 13, so very few genuine users should be affected). (I remember this being mentioned on the Phantom mailing list a few months back, but I don't know if the exact JS to use was described.) More generally you could use a combination of user-agent matching up with feature detection. E.g. if a browser claims to be "Chrome 23" but does not have a feature that Chrome 23 has (and that Chrome 13 did not have), then get suspicious.
As a user, I hate CAPTCHAs too. But they are quite effective in that they increase the cost for the spammer: he has to write more software or hire humans to read them. (That is why I think easy CAPTCHAs are good enough: the ones that annoy users are those where you have no idea what it says and have to keep pressing reload to get something you recognize.)
One approach (which I believe Google uses) is to show the CAPTCHA conditionally. E.g. users who are logged-in never get shown it. Users who have already done one post this session are not shown it again. Users from IP addresses in a whitelist (which could be built from previous legitimate posts) are not shown them. Or conversely just show them to users from a blacklist of IP ranges.
I know none of those approaches are perfect, sorry.
You could detect phantom on the client-side by checking window.callPhantom property. The minimal script is on the client side is:
var isPhantom = !!window.callPhantom;
Here is a gist with proof of concept that this works.
A spammer could try to delete this property with page.evaluate and then it depends on who is faster. After you tried the detection you do a reload with the post form and a CAPTCHA or not depending on your detection result.
The problem is that you incur a redirect that might annoy your users. This will be necessary with every detection technique on the client. Which can be subverted and changed with onResourceRequested.
Generally, I don't think that this is possible, because you can only detect on the client and send the result to the server. Adding the CAPTCHA combined with the detection step with only one page load does not really add anything as it could be removed just as easily with phantomjs/casperjs. Defense based on user agent also doesn't make sense since it can be easily changed in phantomjs/casperjs.

Google Plus Interactive Posts not displayed on any stream (Client side API)

As the title denotes, looking for insight on reasons why an Interactive Post doesn't show up on any stream (user sharing the post, and to whomever the user is sharing it with).
Brief
Implement client side api of G+ interactive posts
This seems successful
application auth is requested and if granted is displayed in user's "applications list"
intended content, prefill text, etc. are all displayed when the trigger to initiate the share is invoked
no error indicators (that I know of) are displayed when the "Share" button is clicked by the user (the act of actually posting the share).
it is visible in some way only to Google - explained below
Findings
It seems Google is blocking the post because even though the share isn't posted on any stream (origin nor target), I received a warning about violating Google policies as displayed below, indicating that the (http) post was sent/submitted...
further inspection of network activity also displays what looks like (a guess on my part) a spam score (of 8), somehow already pre-determined (another guess on my part):
https://apis.google.com/u/0/_/sharebox/post/?spam=8&hl=en&ozv=...
Questions
Primary question is why would interactive posts not appear on stream? Any debugging tool out there?
IF my guess on spam blocking is accurate, then why would such be the case? For interactive posts (which somehow inherently is a case of some user "promoting" something in the first place) - eg: with a "BUY" calltoactionlabel?
IF my other guess on the content being "pre-tagged" as spam, how/why would that occur. I didn't include it above, but it is a "product page" - the idea of it, which isn't new nor revolutionary, is to give the opportunity for a user to "share" an item he/she just purchased, say in a normal checkout flow?
It's my assumption that implementation was done correctly, no errors reported, etc. - or perhaps it wasn't? Though it seems unlikely, it's "grasping at straws" time..
Further testing/debugging seems unwise given the warning of policy violation - and yes, I've stopped further dev on this to prevent harming my accounts (one personal, one work, both used above for testing this API).
Thanks for any assistance/input.
Note: I've posted this on G+ community (no luck so far) so once this is resolved I'll share the answer there too (or vice versa).
It looks like you are posting the Interactive post from http://localhost or from any private domain url. Google crawler can only allow interactive post from public domain.
As from their website -
Important: Interactive posts will not work when PhotoHunt is hosted at http://localhost:8888 because the Google crawler can only access public URLs to get microdata about the content of the post. In the case of PhotoHunt for Java, you can deploy your app to appspot.com as a public Google App Engine app.