I'm trying to use FireWatir (1.6.5) to access a site using Basic
Authentication and I've been unable to find a solution that works on
Firefox in Linux. Does FireWatir 1.6.5 support Basic Authentication
on Linux? I've been searching the web for 2 days and can't get a
straight answer anywhere as to how to do this.
The only thread I found that seemed helpful was this one (
http://groups.google.com/group/watir-general/browse_thread/thread/d8ab9a177d282ce4/fc1bf2319fb387d8?lnk=gst&q=basic+authentication#fc1bf2319fb387d8).
Aedorn Varanis says " Angrez's fork had the solution so I'm using that
now. Thanks Angrez, works perfectly!", but he doesn't mention what he
did to get things working.
Initially I tried to bypass the authentication dialog box by using:
browser.goto('http://admin:password#172.20.1.1')
However, this generates a "Confirm" dialog which says:
"You are about to log in to the site "172.20.1.1" with the username
"admin"." [Cancel, OK]
This dialog blocks, and the goto call won't return until I click "OK".
Then I tried adding:
browser.startClicker("ok")
browser.goto('http://admin:password#172.20.1.1')
But this ALSO generates the same "Confirm" dialog.
I tested out the startClicker functionality using the unit test /var/
lib/gems/1.8/gems/firewatir-1.6.5/unittests/html/JavascriptClick.html
and it worked fine, which makes me think that using the startClicker
method is NOT the correct way to take care of the Confirm dialog.
Anybody else found a way to get Basic Auth to work, or how to click
the OK on the confirm dialog? I'm at my wits end...
This may be a long ugly workaround, and may also violate the simplicity of watir's philosophy, but since you are at your wits end ...
1) Sahi (http://sahi.co.in/) handles 401 authentication dialogs by converting them into regular web pages.
2) Sahi's proxy needs to be running, and you point your browser to use Sahi's proxy.
3) You can then navigate to your page and just use watir/firewatir to enter username password into a converted 401 authentication web page, (like a regular form).
You would incur the extra load of the proxy, but Sahi is fairly well behaved so you should be able to make it work.
You could post here or on Sahi's forums if you need further assistance.
Hope that helps.
-Narayan
With help from Aedorn Varanis I've got things working on Firefox in
Linux.
Aedorn sent me a "logon" method which issues a jssh command that
checks for an "Authentication Required" dialog and if it exists, fills
in the username/password and submits the dialog.
I've copied and pasted what he sent me below:
You use a method that looks like this:
def logon(username, password, wait=3)
jssh_command = "var length = getWindows().length; var win;var found=false; for(var i = 0; i < length; i++) { win = getWindows()[i]; if(win.document.title == \"Authentication Required\") { found = true; break; }} if(found) { var jsdocument = win.document; var dialog = jsdocument.getElementsByTagName(\"dialog\")[0];"
jssh_command << " jsdocument.getElementsByTagName(\"textbox\")[0].value = \"#{username}\";"
jssh_command << " jsdocument.getElementsByTagName(\"textbox\")[1].value = \"#{password}\";"
jssh_command << " dialog.getButton(\"accept\").click(); }\n"
sleep(wait)
$jssh_socket.send(jssh_command,0)
read_socket()
wait()
end
Then you can call it within its own
thread just before going to the site
with the login requirement:
Thread.new { logon(user, pass) }
#ff.goto("http://some_url.com")
sleep 3
Increase the wait and sleep time if
the page takes awhile to load. If your
main process tries to run while the
command is being sent through the JSSH
socket, it will stall and sit there
forever until killed. Also, there's no
real way to detect if the
authentication window comes up. That
means you need to make sure it always
works the same way every time, or it,
too, causes problems. Finally, the
method will always have to be in
another thread, because once the
authentication window comes up, it
stops all other processing until it
goes away. Other than that, it works.
From this, I was able to subclass the FireWatir::Firefox class with a
new Browser class which supports a "credentials=" method just like the
Celerity::Browser does. So, just like using celerity, you can do:
require 'browser'
browser = Browser.new
browser.credentials = 'user:pass'
browser.goto('http://some.basic.auth.url')
This will automatically fill in the Basic Auth dialog and log you into
the site.
I've posted the contents of my browser.rb file below (notice this
works in ruby+firewatir and jruby+celerity in linux):
ENGINE = defined?(RUBY_ENGINE) ? RUBY_ENGINE : 'ruby'
if ENGINE == 'ruby'
require 'firewatir'
class Browser < FireWatir::Firefox
def initialize(options={})
super(options)
#username = nil
#password = nil
end
def credentials=(string)
username, password = string.split(":")
if username.nil? or password.nil?
raise "Invalid credentials: #{string})"
else
#username = username
#password = password
end
end
def goto(url, wait=3)
if #username.nil? and #password.nil?
return super(url)
else
t = Thread.new { logon(#username, #password, wait) }
result = super(url)
t.join
return result
end
end
private
def logon(username, password, wait)
jssh_command = "
var length = getWindows().length;
var win;
var found = false;
for (var i = 0; i < length; i++) {
win = getWindows()[i];
if(win.document.title == \"Authentication Required\") {
found = true;
break;
}
}
if (found) {
var jsdocument = win.document;
var dialog = jsdocument.getElementsByTagName(\"dialog\")[0];
jsdocument.getElementsByTagName(\"textbox\")[0].value = \"#{username}\";
jsdocument.getElementsByTagName(\"textbox\")[1].value = \"#{password}\";
dialog.getButton(\"accept\").click();
}
\n"
sleep(wait)
$jssh_socket.send(jssh_command,0)
read_socket()
end
end
elsif ENGINE == 'jruby'
require 'celerity'
class Browser < Celerity::Browser; end
else
raise "Ruby ENGINE '#{ENGINE}' not supported."
end
I battled long and hard with this issue until today. Apparently i overlooked the answer many times because it didn't look plausible. However, the solution lies in Firefox's "network.http.phishy-userpass-length" profile configuration. If FireWatir allows you to modify your firefox instance Profile, then you can give the "network.http.phishy-userpass-length" a value of 255 which should make that dialog disappear. check http://kb.mozillazine.org/Network.http.phishy-userpass-length for more details.
Note: With Capybara + selenium-webdriver in Ruby, I did;
require 'capybara'
require 'selenium-webdriver'
profile = Selenium::WebDriver::Firefox::Profile.new
profile['network.http.phishy-userpass-length'] = 255
Capybara::Selenium::Driver.new(:profile => profile, :browser => :firefox)
Related
I'm working on an application that records the screen and it should support terminal services, The problem is actually when the RDP window is minimized the user session goes into UI less mode and there is no screen to capture for the application running on that particular session.
There is a way to handle it by setting a registry value to hold on the UI as described here.
But I do not want to do that and would like to capture the UI less mode status and display the user a message that the RDP window had been minimized/fast user switch has happened and the recording is suspended.
So I decided to enumerate the active sessions and check whether the user session is either idle or UI lesss. But that doesn't help. I did not find any clue about detecting the fast user switch when the RDP window is minimzed after almost spending a day.
I couldn't find any event or an API that I can call to ensure that the screen capture has been failing due to fast user switch / minimized RDP window.
Here is my code,
bool bActive = false;
{
DWORD dwCurrentProcessSessionID = 0;
ProcessIdToSessionId(GetCurrentProcessId(), &dwCurrentProcessSessionID);
PWTS_SESSION_INFO pSessionInfo = 0;
DWORD dwCount = 0;
// Get the list of all terminal sessions
WTSEnumerateSessions(WTS_CURRENT_SERVER_HANDLE, 0, 1, &pSessionInfo, &dwCount);
int dataSize = sizeof(WTS_SESSION_INFO);
// look over obtained list in search of the active session
for (DWORD i = 0; i < dwCount; ++i)
{
WTS_SESSION_INFO si = pSessionInfo[i];
if (_WTS_CONNECTSTATE_CLASS::WTSActive == si.State)
{
// If the current session is active – store its ID
if (dwCurrentProcessSessionID == si.SessionId)
{
// would like to have an API that can identify whether the current RDP session is UI less
if (FunctionToFindCurrentRDPIsUIless(si.SessionId))
{
bActive = false;
}
else
{
bActive = true;
}
break;
}
}
}
}
Any help would be appreciated.
I'm using the videojs-playlist plugin along with Google's videojs-ima plugin. Everything works swimmingly except I am only getting a preload ad before the first video. I want one before each video in the playlist.
Basic setup is boilerplate, but for reference:
this.player = videojs('currentvideo', { autoplay : true, fluid : true });
this.player.playlist(this.playlist);
this.player.playlist.autoadvance(5);
const skippable_linear = {google's test ad};
const options = {
id: 'currentvideo',
adTagUrl: skippable_linear,
debug : true
};
this.player.ima(
options
);
this.player.ima.requestAds();
I have tried various ways of manually calling ads from inside an 'ended' event handler, such as calling requestAds again:
const _this = this;
this.player.on( 'ended', function(){
/* some other stuff */
_this.player.ima.requestAds();
});
This does play an ad where I want it, but
this breaks playlist's 'autoadvance' setting (next video doesn't start playing when the ad is finished), and
this puts the player into "ad display" mode (scrubber is unavailable, etc).
Is there a simple way to just say, "play an ad now" programmatically? I've tried, without joy, to use all of the seemingly applicable methods exposed by both the ima plugin and the contrib-ads plugin it relies on. I'll admit here that this is the first time I've ever had to deal with videos that run ads, so I'm kind of a noob.
I am trying to do the same thing. Just like you I failed when calling player.ima.requestAds() on events. I dug deeper and the best I could come up with is what I share bellow.
According to the videojs-ima API you have to use the setContentWithAdTag method instead of whatever you are using to switch the player content. In our case it is the player.playlist.next method.
I combined the code found in the videojs-ima examples with the original playlist.next to write my own next.
Then quite brutally I overrode the original plugin method.
Here's the code:
player.playlist(myPlayilst);
player.playlist.autoadvance(2);
player.playlistUi(); //videojs-playlist-ui
player.ima({
id: 'video5',
adTagUrl: 'thy adserver request'
});
//override playlist.next
player.playlist.next = function(){
var nextIndex = 0,
playlist = this.player_.playlist,
list = this.player_.playlist();
//everything below is copied directly from the original `next` (except for the "//load with ad")
// Repeat
if (playlist.repeat_) {
nextIndex = playlist.currentIndex_ + 1;
if (nextIndex > list.length - 1) {
nextIndex = 0;
}
} else {
// Don't go past the end of the playlist.
nextIndex = Math.min(playlist.currentIndex_ + 1, list.length - 1);
}
// Make the change
if (nextIndex !== playlist.currentIndex_) {
//load with ad
this.player_.playlist.currentItem(nextIndex);
this.player_.ima.setContentWithAdTag(
this.player_.playlist.currentItem(),
null,
true);
this.player_.ima.requestAds();
/////
return list[playlist.currentItem()];
}
}
You will probably need to override other methods that change the current playback, like playlist.previous.
I use videojs-playlist-ui so in my case it was neccessary to change the onclick handler called switchPlaylistItem_. I used some good old brute force to do that like this:
videojs.getComponent('PlaylistMenuItem').prototype.switchPlaylistItem_ = function(e){
this.player_.playlist.currentItem(this.player_.playlist().indexOf(this.item));
this.player_.ima.setContentWithAdTag(
this.player_.playlist.currentItem(),
null,
true);
this.player_.ima.requestAds();
};
PlaylistMenuItem's prototype should be changed before initializing the player.
This solution works, but it feels hacky, so if anyone can come up with something cleaner, please share!
I ended up forking videojs-playlist, and adding the option to override the player.src method. Feel free to use it:
fw-videojs-playlist
Details on how to use it are all in the github readme (including an example with ima.setContentWithAdTag)
I've been looking into this for awhile now as I have created a client I would love to be able to run in a separate window (In a similar design to the Blizzard launcher or the old Ijji reactor). I was wondering if this was possible. Last week I created a web browser within Visual Basic but I was not happy with the final result at the bars where still stationed around the window. Any helpful tips or advice would be appreciated!
You didn't specify language, so you get it in c#. This might work. Starts chrome in app mode. here is the argument list
http://peter.sh/experiments/chromium-command-line-switches/
url = "--app=http://google.com";
Process[] pname = Process.GetProcessesByName("chrome");
if (pname.Length == 0)
{
chrome = false;
}
else // if chrome is running
{
if (!chrome)
{
Process process = new Process();
process.StartInfo.FileName = "chrome";
process.StartInfo.Arguments = url;
process.StartInfo.WindowStyle = ProcessWindowStyle.Normal;
process.Start();
//Process.Start("chrome", url);
}
chrome = true;
}
I'm trying to create a command based spotify client running on ubuntu/debian. But, I keep on getting in to a problem when trying to login.
The code:
int main() {
sp_session *sp;
sp_error err;
sp_session_callbacks callbacks;
sp_session_config config;
config.api_version = 10;
config.cache_location = "tmp";
config.settings_location = "tmp";
config.application_key = g_appkey;
config.application_key_size = g_appkey_size;
config.user_agent = "name";
config.callbacks = NULL;
err = sp_session_create(&config, &sp);
if (SP_ERROR_OK != err) {
fprintf(stderr, "Unable to create session: %s\n",
sp_error_message(err));
exit(1);
}
return 0;
}
And i get this:
"Unable to create session: Unable to open trace file"
Its error code 26.
Do anyone know what this error message means? Having a hard time finding a good answer for this.
Thx
Credentials are not put in before the call to sp_session_login() and the callback returned when that completes will tell you if the user entered bad credentials through an error code.
Also, in general libspotify will like it better if you provide zero for all unused fields in structs, like so:
memset(&config, 0, sizeof(sp_session_config));
// here goes setup of config struct
That said, sp_session_create() should never block and is not asynchronous.
The file paths (cache and settings) need to be absolute paths to a writable place on disk. Try replacing "tmp" with something like "/tmp/libSpotify" - make sure /tmp/libSpotify or whatever actually exists first.
try adding config.tracefile = NULL;
I believe this is related to the asynchronous nature of chrome extensions.
This section of my code:
alert(tab.title);
chrome.tabs.executeScript(tab.id, {code:"document.title = 'test'"});
Works fine, but as soon as I remove the alert, it stops working. Is there anything I can do to remove the alert but still have the js injected?
EDIT: More Code
tabs is a global array of tab objects.
chrome.tabs.onSelectionChanged.addListener(function (tabId) {
for (var i = 0; i < tabs.length; i++) {
if (tabs[i].id == tabId) {
var tab = tabs[i];
while (i < tabs.length) {//length-1
tabs[i] = tabs[i+1];
i++;
}
tabs.pop();
alert(tab.title);//WHY IS THIS NEEDED
chrome.tabs.executeScript(tab.id, {code:"document.title = document.title.substring(1)"});
return;
}
}
});
I am very confused. Changing it the following solves the problem:
chrome.tabs.executeScript(tab.id, {code:"setTimeout('document.title = document.title.substring(1)',100)"});
However, as soon as I change the delay to 50, the script doesn't get executed again. I would prefer not to have to have to make this delay. Does anyone know whats going on?
I know this is an old question, but if anyone is looking - wrap the chrome.tabs.executeScript method in a timeout.
setTimeout(function(){chrome.tabs.executeScript(tab.id, {code:"setTimeout('document.title = document.title.substring(1)',100)"});},500);
It's certainly not ideal but it gets the job done.
Sounds like you have a race condition. My best guess would be to change the injected code to execute on onLoad.