I'm working on adding WebAuthn support to a newly-minted web site and am running into a problem during the navigator.credentials.get() call. The client is Firefox 85.0 on Fedora 33. In case it matters, the server is Apache httpd on Fedora 33. The token is either a Yubikey 4 or a Yubikey 5NFC (the results are the same). This is the function making the API call. Obviously the credential IDs hard-coded here are for testing, not part of the final product:
function handleUserAuthenticationResponse(r) {
var cid1 = {type: "public-key", id: base64ToArrayBuffer("gL0Ig10uA2tn8L0kn2L9FoGqIPSrqvc1lLBwgQhcVDa200b1P94kPv94T6O1bDZyYRrfLbTrLRsubDxuYUxHCg==")};
var cid2 = {type: "public-key", id: base64ToArrayBuffer("tjW1RPqtAJm69I/qeV7eRFJx6h87J3NPeJ/hhbkjttcCc2BWHQ2v2nueoKBSGabw1eYsT8S+lhJv1l1mYWX+Uw==")};
var options = {
rpID: "http://localhost",
challenge: base64ToArrayBuffer(r.challenge),
allowCredentials: [cid1,cid2],
timeout: 60000
};
if (!window.PublicKeyCredential) {
throw new Error("Unable to access credentials interface");
}
navigator.credentials.get({"publicKey":options})
.then(assertion => handleTokenAssertion(assertion))
.catch(e => {console.log("Error fetching token assertion:",e);});
}
function base64ToArrayBuffer(base64) {
var binary_string = window.atob(base64);
var len = binary_string.length;
var bytes = new Uint8Array(len);
for (var i = 0; i < len; i++) {
bytes[i] = binary_string.charCodeAt(i);
}
return bytes.buffer;
}
function handleTokenAssertion(a) {
alert("Got an assertion!");
}
Everything seems to work, the Yubikey LED blinks, I press the touchpad, but then I get back an exception:
Error fetching token assertion: DOMException: An attempt was made to use an object that is not, or is no longer, usable
This seems to be a bit of a Firefox catch-all. It could indicate that the token doesn't match one of the allowedCredentials[], or perhaps other things. It's hard to tell. The FIDO2 credential on the Yubikey was created with fido2-cred(1) tool packaged with the libfido2 source. In this case the credentialId is from the fido2-cred -M output:
CuCEGL10uPhBmNCY4NsGaAz0gir/68UMGFQn0pfb6tc=
http://localhost
fido-u2f
WMSGBbi6CMINQvnkVRUYcYltDg3pgFlihvtzbRHuwBPipEEAAAAAAAAAAAAAAAAAAAAAAAAAAABAgL0Ig10uA2tn8L0kn2L9FoGqIPSrqvc1lLBwgQhcVDa200b1P94kPv94T6O1bDZyYRrfLbTrLRsubDxuYUxHCqUBAgMmIAEhWCA5itRRCBO0lnsztvPvI1waVZLBCZ1XMJjOvlN2oZmBCyJYILFaRjThs5Paj1sOp81iID1LpUBYHJhp4dizC0eI/RrE
gL0Ig10uA2tn8L0kn2L9FoGqIPSrqvc1lLBwgQhcVDa200b1P94kPv94T6O1bDZyYRrfLbTrLRsubDxuYUxHCg==
MEQCIFfs8PagKhNnDgzxfurVzdkTDVTT6ixKk0ak/2qrbSPUAiAf64w390rX1cyY58JgSC/Ac97w6TLcYKuqxOSn5lxV0g==
<long assertion certificate>
You can see the credentialId on line 5, and that it matches cid1 in the Javascript function. Furthermore, if I request an assertion from the token using this credentialId and all else identical (except the challenge) with fido2-assert -G, everything works fine: I get the assertion and it verifies correctly using fido2-assert -V.
Without a more meaningful diagnostic it's hard to know what to try, so I thought I would ask here and see if anyone has any hints. Perhaps I've made some basic error with either Javascript or the credentials API?
Thanks!
UPDATE: One possibility I thought might be worth trying was removing the scheme from the RP ID but that made no difference.
UPDATE: Looking at the firefox source code, the error is apparently NS_ERROR_DOM_INVALID_STATE_ERR, which covers several different situations but in this case is most likely a translation of U2F_ERROR_INVALID_STATE (in dom/webauthn/U2FHIDTokenManager.h). U2F_ERROR_INVALID_STATE, in turn, is defined in third_party/rust/authenticator/src/u2fhid-capi.h as a simple numerical value (3), with no indication of where the value came from. Perhaps it's defined by the underlying HID driver for the Yubikey, but it's not clear what driver that corresponds to. The hunt continues...
It turns out that the problem was indeed the format of the relying party ID. Based on example code from the net (which may have worked with other browsers or versions of the code?), I initially used the full scheme://domain format for the rpID (so in my code above, http://localhost), but it turns out that what's needed is just the domain (localhost). Modifying the rpID in this way allows the assertion process to succeed.
Initially I thought this did not work, but it turned out that I'd simply forgotten to commit the change. Having belatedly done that, it works.
I am working using Node and Discord.js, making edits to the source code of a Discord bot for a client. As such I won't be able to provide the full source files as the vast majority of the code isn't mine and I'd rather not release the client's code just in case - but I'll be posting the snippets written by me that are relevant to the question.
The task involves making the bot generate an image highlighting the 'daily' items in the Fortnite game shop. Basically, a background/template image, which will have the images of various shop items overlayed onto boxes in the template image. To accomplish this, I've been attempting to use Jimp for the image manipulation/generation involved. However, I've run across a strange issue that only seems to be a problem when the images came from the API that provides the Fortnite item pngs.
This API returns (among other things) a URL to the image, which was what I initially tried to use to read from with Jimp. (Note that I can't actually provide any links to the API docs as it's in a closed beta; I only have access to it because the client gave me their token so I could work on it.) Jimp.read is meant to take an img URL that it processes into a Jimp image - and this seems to work fine when I use an image URL from any other source. When feeding it the URL from this API, though, it causes an exception which console.logs as:
AssertionError [ERR_ASSERTION]: zlib binding closed
(followed by the rest of a stack trace, which I'll post in full down below).
I've been beating my head against a wall for several hours now trying to break through this, Googling, trying to create workarounds, try out alternative libraries, but have still not been able to get anywhere. I tried loading the image into a Buffer and feeding that into Jimp.read, but get the exact same error, word for word. Tried using the new Jimp( ... ) constructor instead but still didn't work.
I've also been Googling to try and find an answer but the zlib binding closed error seems to be extremely uncommon and there were very few mentions of it in any context, and no mentions of it in relation to Jimp that I could find. Googling "zlib binding closed" within quotes provided me only 19 results period. If nothing else, if anyone knows what this error means, that would help me have a better idea where to look to fix it.
I've tried looking into alternatives to the Jimp library, but as far as JavaScript image manipulating libraries go, the Canvas API requires a DOM object and Caman I just couldn't get to install.
I don't generally ask things on StackOverflow but I couldn't find instances of this problem anywhere. Possible solutions or even just explanations of what the error could mean would be extremely helpful, also if anyone has suggestions for a good alternative to Jimp in the case I can't fix this.
(Code snippets/stack traces below, I probably missed some important stuff since I'm tired and completely brainfried from working on this, so let me know if you need anything else from me)
URL Attempt:
Jimp.read("https://image.fnbr.co/outfit/5b90ec38262b40c2dcc98379/icon.png")
.then(image => {
message.channel.send("jimp", {
file: image
});
})
.catch(err => {
console.log(err);
});") // Should just return a URL string
.then(image => {
message.channel.send("jimp", {
file: image
});
})
.catch(err => {
console.log(err);
});
Buffer Attempt:
request.get("https://image.fnbr.co/outfit/5b90ec38262b40c2dcc98379/icon.png", function(error, response, body) {
if (!error && response.statusCode == 200) {
var buffer = new Buffer(body);
Jimp.read(buffer)
.then(image => {
message.channel.send("jimp", {
file: image
});
})
.catch(err => {
console.log(err);
});
} else {
console.log("8(");
}
});
^ Ultimately the above will be getting the image URLs based on the 'daily' results from the shop but for now I'm just trying to get them to work on a hard-coded URL. All URLs from that API follow the same format as the one used here.
Full console.log(err) Console Output:
{ AssertionError [ERR_ASSERTION]: zlib binding closed
at Inflate._processChunk (C:\Users\(user)\Documents\dev\(project)\node_modules\pngjs\lib\sync-inflate.js:108:3)
at zlibBufferSync (C:\Users\(user)\Documents\dev\(project)\node_modules\pngjs\lib\sync-inflate.js:151:17)
at inflateSync (C:\Users\(user)\Documents\dev\(project)\node_modules\pngjs\lib\sync-inflate.js:155:10)
at module.exports (C:\Users\(user)\Documents\dev\(project)\node_modules\pngjs\lib\parser-sync.js:79:20)
at Object.exports.read [as image/png] (C:\Users\(user)\Documents\dev\(project)\node_modules\pngjs\lib\png-sync.js:10:10)
at Jimp.parseBitmap (C:\Users\(user)\Documents\dev\(project)\node_modules\#jimp\core\dist\utils\image-bitmap.js:117:53)
at new Jimp (C:\Users\(user)\Documents\dev\(project)\node_modules\#jimp\core\dist\index.js:425:32)
at _construct (C:\Users\(user)\Documents\dev\(project)\node_modules\#jimp\core\dist\index.js:100:393)
at C:\Users\(user)\Documents\dev\(project)\node_modules\#jimp\core\dist\index.js:885:5
at Promise (<anonymous>)
generatedMessage: false,
name: 'AssertionError [ERR_ASSERTION]',
code: 'ERR_ASSERTION',
actual: undefined,
expected: true,
operator: '==',
methodName: 'constructor' }
Managing packages with npm, running from a Windows computer.
I was having the same issue.
In my case I was testing with node 10.15.3 but when I pkged my app, the node version embedded was on version 8. Since ZLIB is not available in that version, the assert failed. That is the reason why I was seeing the error.
Here is the issue that has been nagging for weeks and all solutions found online do not seem to work... ie. wait for ajax, etc...
here is versions of gems:
capybara (2.10.1, 2.7.1)
selenium-webdriver (3.0.1, 3.0.0)
rspec (3.5.0)
running ruby 2.2.5
ruby 2.2.5p319 (2016-04-26 revision 54774) [x64-mingw32]
in the env.rb
Capybara.register_driver :selenium do | app |
browser = (ENV['browser'] || 'firefox').to_sym
Capybara::Driver::Selenium.new(app, :browser => browser.to_sym, :resynchronize => true)
Capybara.default_max_wait_time = 5
end
Here is my dynamicpage.feature
Given I visit page X
Then placeholder text appears
And the placeholder text is replaced by the content provided by the json service
and the step.rb
When(/^I visit page X$/) do
visit('mysite.com/productx/')
end
When(/^placeholder text appears$/) do
expect(page).to have_css(".text-replacer-pending")
end
Then(/^the placeholder text is replaced by the content provided by the json service$/) do
expect(page).to have_css(".text-replacer-done")
end
the webpage in question, which I cannot add it here as it is not publicly accessible, contains the following on page load:
1- <span class="text-replacer-pending">Placeholder Text</span>
after a call to an external service (which provides the Json data), the same span class gets refreshed/updated to the following;
2- <span class="text-replacer-done">Correct Data</span>
The problem I have with the "visit" method in capybara + selenium is that as soon as it visits the page, it thinks everything loaded and freezes the browser, and it never lets the service be called to dynamically update the content.
I tried the following solutions but without success:
Capybara.default_max_wait_time = 5
Capybara::Driver::Selenium.new(app, :browser => browser.to_sym, :resynchronize => true)
add sleep 5 after the visit method
wait for ajax solution from several websites, etc...
adding after hooks
etc...
I am at a complete loss why "visit" can't wait or at least provide a simple solution to an issue i am sure is very common.
I am aware of the capybara methods that wait and those that don't wait such as 'visit' but the issue is;
there is no content that goes from hidden to displayed
there is there is no user interaction either, just the content is getting updated.
also unsure if this is a capybara issue or a selenium or both.
Anyhow have insight on any solutions? i am fairly new to ruby and cucumber so specifically what code goes in what file/folder would be much appreciated.
Mel
Restore wait_until method (add it to your spec_helpers.rb)
def wait_until(timeout = DEFAULT_WAIT_TIME)
Timeout.timeout(timeout) do
sleep(0.1) until value = yield
value
end
end
And then:
# time in seconds
wait_until(20) { has_no_css?('.text-replacer-pending') }
expect(page).to have_css(".text-replacer-done")
#maxple and #nattf0dd
Just to close the loop on our issue here...
After looking at this problem from a different angle,
we finally found out Cucumber/Capybara/ is not a problem at all :-)
The issue we are having lies with the browser Firefox driver (SSL related), since we have no issues when running the same test with the Chrome driver.
I do appreciate the replies and suggestions and will keep those in mind for future.
thanks again!
This is the error message that I get:
Failed to execute 'postMessage' on 'DOMWindow': The target origin provided
('https://www.youtube.com') does not match the recipient window's origin
('http://localhost:9000').
I've seen other similar problems where the target origin is http://www.youtube.com and the recipient origin is https://www.youtube.com, but none like mine where the target is https://www.youtube.com and the origin is http://localhost:9000.
I don't get the problem. What is the problem?
How can I fix it?
I believe this is an issue with the target origin being https. I suspect it is because your iFrame url is using http instead of https. Try changing the url of the file you are trying to embed to be https.
For instance:
'//www.youtube.com/embed/' + id + '?showinfo=0&enablejsapi=1&origin=http://localhost:9000';
to be:
'https://www.youtube.com/embed/' + id + '?showinfo=0&enablejsapi=1&origin=http://localhost:9000';
Just add the parameter "origin" with the URL of your site in the paramVars attribute of the player, like this:
this.player = new window['YT'].Player('player', {
videoId: this.mediaid,
width: '100%',
playerVars: {
'autoplay': 1,
'controls': 0,
'autohide': 1,
'wmode': 'opaque',
'origin': 'http://localhost:8100'
},
}
Setting this seems to fix it:
this$1.player = new YouTube.Player(this$1.elementId, {
videoId: videoId,
host: 'https://www.youtube.com',
You can save the JavaScript into local files:
https://www.youtube.com/player_api
https://s.ytimg.com/yts/jsbin/www-widgetapi-vfluxKqfs/www-widgetapi.js
Into the first file, player_api put this code:
if(!window.YT)var YT={loading:0,loaded:0};if(!window.YTConfig)var YTConfig={host:"https://www.youtube.com"};YT.loading||(YT.loading=1,function(){var o=[];YT.ready=function(n){YT.loaded?n():o.push(n)},window.onYTReady=function(){YT.loaded=1;for(var n=0;n<o.length;n++)try{o[n]()}catch(i){}},YT.setConfig=function(o){for(var n in o)o.hasOwnProperty(n)&&(YTConfig[n]=o[n])}}());
Into the second file, find the code: this.a.contentWindow.postMessage(a,b[c]);
and replace it with:
if(this._skiped){
this.a.contentWindow.postMessage(a,b[c]);
}
this._skiped = true;
Of course, you can concatenate into one file - will be more efficient.
This is not a perfect solution, but it's works!
My Source : yt_api-concat
Make sure you are loading from a URL such as:
https://www.youtube.com/embed/HIbAz29L-FA?modestbranding=1&playsinline=0&showinfo=0&enablejsapi=1&origin=https%3A%2F%2Fintercoin.org&widgetid=1
Note the "origin" component, as well as "enablejsapi=1". The origin must match what your domain is, and then it will be whitelisted and work.
In my case this had to do with lazy loading the iframe. Removing the iframe HTML attribute loading="lazy" solved the problem for me.
I got the same error. My mistake was that the enablejsapi=1 parameter was not present in the iframe src.
You also get this message when you do not specify a targetOrigin in calls to window.postMessage().
In this example we post a message to the first iFrame and use * as target, which should allow communication to any targetOrigin.
window.frames[0].postMessage({
message : "Hi there",
command :"hi-there-command",
data : "Some Data"
}, '*')
Try using window.location.href for the url to match the window's origin.
Remove DNS Prefetch will solve this issue.
If you're using WordPress, add this line in your theme's functions.php
remove_action( 'wp_head', 'wp_resource_hints', 2 );
There could be any of the following, but all of them lead into DOM not loaded before its accessed by the javascript.
So here is what you have to ensure before actually calling JS code:
* Make sure the container has loaded before any javascript is called
* Make sure the target URL is loaded in whatever container it has to
I came across the similar issue but on my local when I am trying to have my Javascript run well before onLoad of the main page which causes the error message. I have fixed it by simply waiting for whole page to load and then call the required function.
You could simply do this by adding a timeout function when page has loaded and call your onload event like:
window.onload = new function() {
setTimeout(function() {
// some onload event
}, 10);
}
that will ensure what you are trying will execute well after onLoad is trigger.
In my instance at least this seems to be a harmless "not ready" condition that the API retries until it succeeds.
I get anywhere from two to nine of these (on my worst-case-tester, a 2009 FossilBook with 20 tabs open via cellular hotspot).... but then the video functions properly. Once it's running my postMessage-based calls to seekTo definitely work, haven't tested others.
It looks it's only a Chrome security system to block repeated requests, using CORB.
https://www.chromestatus.com/feature/5629709824032768
In my case, YouTube was blocking Access after the first load of the same webpage which has many video API data request, high payload.
For pages with low payload, the issue does not occur.
In Safari and other non Chronuim based browsers, the issue does not occur.
If I load the webpage in a new browser, the issue does not occur, when I reload the same page, the issue appears.
In some cases (as one commenter mentioned) this might be caused if you are moving the player within DOM, like append or etc..
This helped me (with Vue.js)
Found here vue-youtube
mounted() {
window.YTConfig = {
host: 'https://www.youtube.com/iframe_api'
}
const host = this.nocookie ? 'https://www.youtube-nocookie.com' : 'https://www.youtube.com'
this.player = player(this.$el, {
host,
width: this.width,
height: this.height,
videoId: this.videoId,
playerVars: this.playerVars
})
...
}
UPDATE:
Working like a charm like this:
...
youtube(
video-id="your_video_code_here"
nocookie
)
...
data() {
return {
playerVars: {
origin: window.location.href,
},
};
},
I think the description of the error is misleading and has originally to do with wrong usage of the player object.
I had the same issue when switching to new Videos in a Slider.
When simply using the player.destroy() function described here the problem is gone.
I had this same problem and it turns out it was because I had the Chrome extension "HTTPS Everywhere" running. Disabling the extension solved my problem.
This exact error was related to a content block by Youtube when "playbacked on certain sites or applications". More specifically by WMG (Warner Music Group).
The error message did however suggest that a https iframe import to a http site was the issue, which it wasn't in this case.
You could change your iframe to be like this and add origin to be your current website. It resolves error on my browser.
<iframe class="test-testimonials-youtube-group" type="text/html" width="100%" height="100%"
src="http://www.youtube.com/embed/HiIsKeXN7qg?enablejsapi=1&origin=http://localhost:8000"
frameborder="0">
</div>
ref: https://developers.google.com/youtube/iframe_api_reference#Loading_a_Video_Player
Just wishing to avoid the console error, I solved this using a similar approach to Artur's earlier answer, following these steps:
Downloaded the YouTube Iframe API (from https://www.youtube.com/iframe_api) to a local yt-api.js file.
Removed the code which inserted the www-widgetapi.js script.
Downloaded the www-widgetapi.js script (from https://s.ytimg.com/yts/jsbin/www-widgetapi-vfl7VfO1r/www-widgetapi.js) to a local www-widgetapi.js file.
Replaced the targetOrigin argument in the postMessage call which was causing the error in the console, with a "*" (indicating no preference - see https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage).
Appended the modified www-widgetapi.js script to the end of the yt-api.js script.
This is not the greatest solution (patched local script to maintain, losing control of where messages are sent) but it solved my issue.
Please see the security warning about removing the targetOrigin URI stated here before using this solution - https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage
Patched yt-api.js example
Adding origin=${window.location.host} or "*" is not enough.
Add https:// before it and it will work.
Also, make sure that you are using an URL that can be embedded: take the video ID out and concatenate a string that has the YouTube video prefix and the video ID + embed definition.
I think we could customize the sendMessage of the YT.Player
playerOptions.playerVars.origin = window.location.origin or your domain.
this.youtubePlayer = new YT.Player(element,playerOptions);
this.youtubePlayer.sendMessage = function (a) {
a.id = this.id, a.channel = "widget", a = JSON.stringify(a);
var url = new URL(this.h.src), origin = url.searchParams.get("origin");
if (origin && this.h.contentWindow) {
this.h.contentWindow.postMessage(a, origin)
}
}
I used this function to resolve in my project.
Extending #Hokascha's answer above it was also lazy loading for me being automatically added by WordPress. This code will remove all lazy loading on the site's iframes (add to functions.php):
function disable_post_content_iframe_lazy_loading( $default, $tag_name, $context ) {
if ( 'iframe' === $tag_name ) {
return false;
}
return $default;
}
add_filter('wp_lazy_loading_enabled', 'disable_post_content_iframe_lazy_loading', 10, 3);
I got a similar error message in my attempt to embed a Stripe pricing table when:
Adding the embed code via PHP through a custom WordPress short code
Or by appending the code to the page dynamically with JavaScript (Even a using a setTimeout() delay to ensure the DOM was loaded didn't work).
I was able to solve this on my WordPress site by adding the code to the WordPress page itself using plain html code in the block editor.
mine was:
<youtube-player
[videoId]="'paxSz8UblDs'"
[playerVars]="playerVars"
[width]="291"
[height]="194">
</youtube-player>
I just removed the line with playerVars, and it worked without errors on console.
You can try :
document.getElementById('your_id_iframe').contentWindow.postMessage('your_message', 'your_domain_iframe')
I was also facing the same issue then I visit official Youtube Iframe Api where i found this:
The user's browser must support the HTML5 postMessage feature. Most modern browsers support postMessage
and wander to see that official page was also facing this issue. Just Visit official Youtube Iframe Api and see console logs. My Chrome version is 79.0.3945.88.
I can see, in Chrome Developer tools, loading time, time it took to get a particular resource from server and other info, for all of the resources in a webpage.
I want to capture these stats using JavaScript. How is it possible?
there is window.performance object available, but only for the requested page, not for page resources.
Is there any way to access performance object of all of the page resources.
You should be able to use window.performance.getEntries() to get resource-specific stats:
var resource = window.performance.getEntries()[0];
console.log(resource.entryType); // "resource"
console.log(resource.duration); // 39.00000000430737
console.log(resource.startTime); // 218.0000000007567
Sample from the above link:
There is still a bug in latest version of chrome - 29.0.1547.76 m
When you raise an xmlhttprequest, lets say while downloading an image, you can see that the resource is downloaded with status code 200 OK in network tab, but the performance.getEntries() or performance.getEntriesByName(resourceUrl) doesn't list the resource entry. When the page load is complete and you evaluate performance.getEntriesByName(resourceUrl) in console, it lists properly. So, there is a lag in chrome while populating the resource entries in performance entries?
In IE10, this works perfectly fine.
window.performance.getEntries()
may return not all resources. after bufferful some records is disapear
need check it before it happend
head code part
var storedEntries = [];
var updateStoredEntries = p => {
storedEntries.concat(
p.getEntries().filter(rec => /yourRegExp/.test(rec.name))
)
};
performance.addEventListener('resourcetimingbufferfull', e => {
updateStoredEntries(e.target)
});
...
later part
updateStoredEntries(performance)