I've been reading the MDN docs about nsicookieservice and I'm interested in the notifications of this service: cookie-changed and cookie-rejected. Does that mean that we can get a list of the changed or rejected cookies? Would that be possible by doing somthing like this:
var cookieSvc = Components.classes["#mozilla.org/cookieService;1"]
.getService(Components.interfaces.nsICookieService);
var cookies=cookieSvc.cookie-changed;
Thank you for the explanation.
I reread the documentation(I really did) and searched in the source codes of many extensions. The problem that the extension that i'm building is bootstarpped for firefox for android but I'm not using SDK. Based on what I understood I wrote this:
var cookieMonster = {
//cookieManager: null,
current: null,
observerService: null,
cookieService: null,
init: function() {
this.observerService = Components.classes["#mozilla.org/observer-service;1"].getService(Components.interfaces.nsIObserverService);
this.observerService.addObserver(this, "cookie-changed", false);
this.cookieService = Components.classes["#mozilla.org/cookieService;1"].getService(Components.interfaces.nsICookieService);
// this.cookieManager = Components.classes["#mozilla.org/cookiemanager;1"].getService(Components.interfaces.nsICookieManager);
},
uninit: function() {
//var observerService = Components.classes["#mozilla.org/observer-service;1"].getService(Components.interfaces.nsIObserverService);
this.observerService.removeObserver(this, "cookie-changed", false);
//this.cookieManager = Components.classes["#mozilla.org/cookiemanager;1"].getService(Components.interfaces.nsICookieManager);
},
observe: function(subject, topic, data) {
if (topic != 'cookie-changed') { this.current= "no cookie changed"; return; }
try {
// if (!ghostery.prefs.cookieProtect) { return; }
this.current="there is a chnged cookie!!!";
if ( (data == 'added') || (data == 'changed') ) {
var cookie = subject.QueryInterface(Components.interfaces.nsICookie2);
this.current = "name "+cookie.name+" host "+cookie.host;
}
} catch (err) {}
}
};
Then I do this to add the observer when I load the page:
let addListener = function() {
window.BrowserApp.deck.addEventListener("load", cookieMonster.init, false);
window.NativeWindow.toast.show(cookieMonster.current, "long");
};
if(window.BrowserApp.deck) {
// BrowserApp.deck (and maybe whole BrowserApp?) has been initialized
addListener();
}
else {
// use the chrome window to wait for BrowserApp to initialize
window.BrowserApp.deck.addEventListener("UIReady", addListener);
}
That doesn't work and I don't find any error in the logcat which confuse me more.I'm really stuck and I need your help.
Yes, your add-on can receive notifications about cookies, but you don't receive them via the cookies manager, but the general purpose nsIObserverService.
XUL overlay add-ons should use the nsIObserverService directly.
SDK add-ons will want to use the system/events module instead, which is a bit higher level and does clean up after itself.
There is also a list of the most commonly used notification types.
Related
How to get the following list from the Instagram account using the access token
I tried everything but not work.
here some API link which I tried before but none of them work.
I tried this one https://www.instagram.com/urvish_._/?__a=1
also this one
I tried but nothing can help me.
You can get the following (or also follower) list using the code below. Steps:
Make sure you're logged in on instagram.com
Open the API link: https://www.instagram.com/urvish_._/?__a=1 (your target username here is urvish_._)
Open the browser console: normally Ctrl+Shift+J on Windows/Linux or ⌘+Option+J on Mac
Paste this code and press Enter:
const GRAPHQL_MAX_PER_PAGE = 50;
async function getList() {
let pageLimit = 200; // from my testing
let baseInfo = JSON.parse(document.getElementsByTagName('body')[0].innerText);
let userId = baseInfo.graphql.user.id;
let config = { user_edge: 'edge_follow', query_hash: 'd04b0a864b4b54837c0d870b0e77e076', total_count: baseInfo.graphql.user.edge_follow.count };
// for followers instead of followings:
// { user_edge: 'edge_followed_by', query_hash: 'c76146de99bb02f6415203be841dd25a', total_count: baseInfo.graphql.user.edge_followed_by.count }
let after = null, hasNext = true, thisList = [];
for (pageCount = 1; hasNext && (pageCount <= pageLimit); ++pageCount) {
try {
let response = await fetch(`https://www.instagram.com/graphql/query/?query_hash=${config.query_hash}&variables=` + encodeURIComponent(JSON.stringify({
id: userId, include_reel: true, fetch_mutual: true, first: GRAPHQL_MAX_PER_PAGE, after: after
})));
if (!response.ok) {
console.warn(`Failed at page number ${pageCount.toLocaleString()}. HTTP status ${response.status}: ${response.statusText}.`);
break;
}
try {
response = await response.json();
} catch (error) {
console.error(`You may need to verify your account. Stopping. Failed at page number ${pageCount.toLocaleString()}.`, error);
break;
}
hasNext = response.data.user[config.user_edge].page_info.has_next_page
after = response.data.user[config.user_edge].page_info.end_cursor
thisList = thisList.concat(response.data.user[config.user_edge].edges.map(({ node }) => {
return {
id: node.id,
username: node.username,
full_name: node.full_name,
profile_pic_url: node.profile_pic_url,
};
}));
} catch (error) {
console.warn(`Error at page number ${pageCount.toLocaleString()}:`, error);
}
console.log(`${thisList.length.toLocaleString()} of ${config.total_count.toLocaleString()} fetched so far`);
}
console.info(`${thisList.length.toLocaleString()} fetched.`);
console.log(thisList);
}
getList()
Browser console showing a fetched list after code execution
In the code I've set the page limit to 200 so you can get up to 10,000 of your followings.
PS: For a way to visualise your lists and get more details, you can try Instagram Lists, a tool I made.
I have recently followed a tutorial over on Thinkster for creating a web app using Angular and Firebase.
The tutorial uses the Firebase simpleLogin method allows a 'profile' to be created that includes a username.
Factory:
app.factory('Auth', function($firebaseSimpleLogin, $firebase, FIREBASE_URL, $rootScope) {
var ref = new Firebase(FIREBASE_URL);
var auth = $firebaseSimpleLogin(ref);
var Auth = {
register: function(user) {
return auth.$createUser(user.email, user.password);
},
createProfile: function(user) {
var profile = {
username: user.username,
md5_hash: user.md5_hash
};
var profileRef = $firebase(ref.child('profile'));
return profileRef.$set(user.uid, profile);
},
login: function(user) {
return auth.$login('password', user);
},
logout: function() {
auth.$logout();
},
resolveUser: function() {
return auth.$getCurrentUser();
},
signedIn: function() {
return !!Auth.user.provider;
},
user: {}
};
$rootScope.$on('$firebaseSimpleLogin:login', function(e, user) {
angular.copy(user, Auth.user);
Auth.user.profile = $firebase(ref.child('profile').child(Auth.user.uid)).$asObject();
console.log(Auth.user);
});
$rootScope.$on('$firebaseSimpleLogin:logout', function() {
console.log('logged out');
if (Auth.user && Auth.user.profile) {
Auth.user.profile.$destroy();
}
angular.copy({}, Auth.user);
});
return Auth;
});
Controller:
$scope.register = function() {
Auth.register($scope.user).then(function(user) {
return Auth.login($scope.user).then(function() {
user.username = $scope.user.username;
return Auth.createProfile(user);
}).then(function() {
$location.path('/');
});
}, function(error) {
$scope.error = error.toString();
});
};
At the very end of the tutorial there is a 'next steps' section which includes:
Enforce username uniqueness-- this one is tricky, check out Firebase priorities and see if you can use them to query user profiles by username
I have searched and searched but can't find a clear explanation of how to do this, particularly in terms of the setPriority() function of Firebase
I'm quite the Firebase newbie so any help here would be gratefully recieved.
There are a few similar questions, but I can't seem to get my head around how to sort this out.
Enormous thanks in advance.
EDIT
From Marein's answer I have updated the register function in my controller to:
$scope.register = function() {
var ref = new Firebase(FIREBASE_URL);
var q = ref.child('profile').orderByChild('username').equalTo($scope.user.username);
q.once('value', function(snapshot) {
if (snapshot.val() === null) {
Auth.register($scope.user).then(function(user) {
return Auth.login($scope.user).then(function() {
user.username = $scope.user.username;
return Auth.createProfile(user);
}).then(function() {
$location.path('/');
});
}, function(error) {
$scope.error = error.toString();
});
} else {
// username already exists, ask user for a different name
}
});
};
But it is throwing an 'undefined is not a function' error in the line var q = ref.child('profile').orderByChild('username').equalTo($scope.user.username);. I have commented out the code after and tried just console.log(q) but still no joy.
EDIT 2
The issue with the above was that the Thinkster tutorial uses Firebase 0.8 and orderByChild is available only in later versions. Updated and Marein's answer is perfect.
There are two things to do here, a client-side check and a server-side rule.
At the client side, you want to check whether the username already exists, so that you can tell the user that their input is invalid, before sending it to the server. Where exactly you implement this up to you, but the code would look something like this:
var ref = new Firebase('https://YourFirebase.firebaseio.com');
var q = ref.child('profiles').orderByChild('username').equalTo(newUsername);
q.once('value', function(snapshot) {
if (snapshot.val() === null) {
// username does not yet exist, go ahead and add new user
} else {
// username already exists, ask user for a different name
}
});
You can use this to check before writing to the server. However, what if a user is malicious and decides to use the JS console to write to the server anyway? To prevent this you need server-side security.
I tried to come up with an example solution but I ran into a problem. Hopefully someone more knowledgeable will come along. My problem is as follows. Let's say your database structure looks like this:
{
"profiles" : {
"profile1" : {
"username" : "Nick",
"md5_hash" : "..."
},
"profile2" : {
"username" : "Marein",
"md5_hash" : "..."
}
}
}
When adding a new profile, you'd want to have a rule ensuring that no profile object with the same username property exists. However, as far as I know the Firebase security language does not support this, with this data structure.
A solution would be to change the datastructure to use username as the key for each profile (instead of profile1, profile2, ...). That way there can only ever be one object with that username, automatically. Database structure would be:
{
"profiles" : {
"Nick" : {
"md5_hash" : "..."
},
"Marein" : {
"md5_hash" : "..."
}
}
}
This might be a viable solution in this case. However, what if not only the username, but for example also the email has to be unique? They can't both be the object key (unless we use string concatenation...).
One more thing that comes to mind is to, in addition to the list of profiles, keep a separate list of usernames and a separate list of emails as well. Then those can be used easily in security rules to check whether the given username and email already exist. The rules would look something like this:
{
"rules" : {
".write" : true,
".read" : true,
"profiles" : {
"$profile" : {
"username" : {
".validate" : "!root.child('usernames').child(newData.val()).exists()"
}
}
},
"usernames" : {
"$username" : {
".validate" : "newData.isString()"
}
}
}
}
However now we run into another problem; how to ensure that when a new profile is created, the username (and email) are also placed into these new lists? [1]
This in turn can be solved by taking the profile creation code out of the client and placing it on a server instead. The client would then need to ask the server to create a new profile, and the server would ensure that all the necessary tasks are executed.
However, it seems we have gone very far down a hole to answer this question. Perhaps I have overlooked something and things are simpler than they seem. Any thoughts are appreciated.
Also, apologies if this answer is more like a question than an answer, I'm new to SO and not sure yet what is appropriate as an answer.
[1] Although maybe you could argue that this does not need to be ensured, as a malicious user would only harm themselves by not claiming their unique identity?
I had a similar problem. But it was after registering the user with password and email. In the user profile could save a user name that must be unique and I have found a solution, maybe this can serve you.
Query for username unique in Firebase
var ref = new Firebase(FIREBASE_URL + '/users');
ref.orderByChild("username").equalTo(profile.username).on("child_added", function(snapshot) {
if (currentUser != snapshot.key()) {
scope.used = true;
}
});
ref.orderByChild("username").equalTo(profile.username).once("value", function(snap) {
//console.log("initial data loaded!", Object.keys(snap.val()).length === count);
if (scope.used) {
console.log('username already exists');
scope.used = false;
}else{
console.log('username doesnt exists, update it');
userRef.child('username').set(profile.username);
}
});
};
I have serious issues loading binary image data into a simple image-element. I coded a cordova app (using Sencha touch) which loads images the following way:
xhr.open('GET', imageUrl, true);
xhr.responseType = 'blob';
xhr.addEventListener('load', function () {
if (xhr.status === 200) {
// onload needed since Google Chrome doesn't support addEventListener for FileReader
fileReader.onload = function (evt) {
image.setSrc(evt.target.result);
};
// Load blob as Data URL
fileReader.readAsDataURL(xhr.response);
}
}, false);
On Android 5 and 4.4 (these are the ones I tested) it works like a charm. Now I ran it Android 4.1 on an ASUS Tablet and the onload callback doesn't get fired. When I throw a blob in the readAsDataURL-function, at least the onload callback is fired, but the image doesn't show any image as well :(
Has anyone a suggestion, what the failure could be or what I'm doing wrong?
Ah, finally I got it to work on Android 4.1.1 (ASUS Tablet) with the following code. Another issue was, that saving an arraybuffer response from the xhr could not simply serialized, so I converted the stuff to string. Also I receive the blob taking into account, that on some systems the Blob object simply isn't there:
function arrayBufferToString(buf) {
return String.fromCharCode.apply(null, new Uint8Array(buf));
};
function stringToArrayBuffer(str) {
var buf = new ArrayBuffer(str.length*2); // 2 bytes for each char
var bufView = new Uint8Array(buf);
for (var i=0, strLen=str.length; i<strLen; i++) {
bufView[i] = str.charCodeAt(i);
}
return buf;
};
function getBlob(content, type) {
var blob = null;
// Android 4 only has the deprecated BlobBuilder :-(
try {
blob = new Blob([content], {type: type});
} catch(e) {
window.BlobBuilder = window.BlobBuilder || window.WebKitBlobBuilder ||
window.MozBlobBuilder || window.MSBlobBuilder;
if (window.BlobBuilder)
{
var bb = new BlobBuilder();
bb.append(content);
blob = bb.getBlob(type);
}
}
return blob;
};
cachedFile = getCachedFile(...); // not of interest here, I think :-)
if (cachedFile)
{
callback.apply(this, [window.webkitURL.createObjectURL(getBlob(stringToArrayBuffer(cachedFile.data), 'image/jpeg'))]);
}
else {
xhr.open('GET', imageUrl, true);
xhr.responseType = 'arraybuffer';
xhr.addEventListener('load', function () {
if (xhr.status === 200) {
cachedFile = {
url: imageUrl,
data: arrayBufferToString(xhr.response)
};
addCachedFile(cachedFile); // not of interest here, I think :-)
callback.apply(this, [window.webkitURL.createObjectURL(getBlob(xhr.response, 'image/jpeg'))]);
}
}, false);
// Send XHR
xhr.send();
}
Edit: Just did a little change and now used the Uint8Array Class instead of the Uint16Array Class because I got errors: "RangeError: byte length of Uint16Array should be a multiple of 2". Now it works well.
Edit2: Just saw, that the above code doesn't work out in all situations because of the usage of Uint8Array resp. Uint16Array.
Now I think I have a solid solution: I convert the binary responded by the image url into a base64 using canvas with the function from here http://appcropolis.com/blog/web-technology/javascript-encode-images-dataurl/ . Takes a little time, but still a working solution :)
How do I set the CORS headers for M3U8 file streaming in Chromecast? In my sender (Android) I am setting the Metadata and MediaInfo like this:
metaData = new MediaMetadata(MediaMetadata.MEDIA_TYPE_MOVIE);
metaData.putString(MediaMetadata.KEY_TITLE, "Demo Video");
MediaInfo mediaInfo = new MediaInfo.Builder(
"http://playertest.longtailvideo.com/adaptive/bbbfull/bbbfull.m3u8")
.setContentType("application/vnd.apple.mpegurl")
.setStreamType(MediaInfo.STREAM_TYPE_BUFFERED)
.setMetadata(metaData)
.build();
player.load(client, mediaInfo, true)
.setResultCallback(new ResultCallback<RemoteMediaPlayer.MediaChannelResult>() {
#Override
public void onResult(RemoteMediaPlayer.MediaChannelResult mediaChannelResult) {
Status status = mediaChannelResult.getStatus();
if (status.isSuccess()) {
}
}
});
My onLoad method is set up like this:
mediaManager.onLoad = function(event) {
console.log("### Media Manager - LOAD: " + JSON.stringify(event));
if(mediaPlayer !== null) {
mediaPlayer.unload(); // Ensure unload before loading again
}
if (event.data['media'] && event.data['media']['contentId']) {
var url = event.data['media']['contentId'];
mediaHost = new cast.player.api.Host({
'mediaElement': mediaElement,
'url': url
});
mediaHost.onError = function (errorCode) {
console.error('### HOST ERROR - Fatal Error: code = ' + errorCode);
if (mediaPlayer !== null) {
mediaPlayer.unload();
}
}
var initialTimeIndexSeconds = event.data['media']['currentTime'] || 0;
// TODO: real code would know what content it was going to access and this would not be here.
var protocol = null;
var parser = document.createElement('a');
parser.href = url;
var ext = ext = parser.pathname.split('.').pop();
if (ext === 'm3u8') {
protocol = cast.player.api.CreateHlsStreamingProtocol(mediaHost);
} else if (ext === 'mpd') {
protocol = cast.player.api.CreateDashStreamingProtocol(mediaHost);
} else if (ext === 'ism/') {
protocol = cast.player.api.CreateSmoothStreamingProtocol(mediaHost);
}
console.log('### Media Protocol Identified as ' + ext);
if (protocol === null) {
mediaManager['onLoadOrig'](event); // Call on the original callback
} else {
mediaPlayer = new cast.player.api.Player(mediaHost);
mediaPlayer.load(protocol, initialTimeIndexSeconds);
}
}
}
However, I am getting this error:
XMLHttpRequest cannot load http://playertest.longtailvideo.com/adaptive/bbbfull/bbbfull.m3u8. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin '----' is therefore not allowed access.
For Chromecast, how do I set the CORS headers for Chromecast?
Probably too late, but just came across with the same issue and get it done by the approach mentioned below.
I didn't get a way to add headers on sender app side so, sharing my own experience. I get the CORS issue fixed upon firstly confirming that my server is supporting CORS. And then for playing the media on chromecast, i was needed to add gstatic.com and in my case another one as well as allowed domains on server, which is in-fact the whole idea of CORS, that each domain should be known to our server. And that's it.
Note: Be very much sure to go through this official documentation. But for being a beginner it may appear a bit tricky to grab all the stuff from here. So shared own experience as well.
I have a really weird scenario that I'm stuck on. I have a ASP.Net MVC 4 app where I'm authenticating a user and creating an authCookie and adding it to the response's cookies then redirecting them to the target page:
if (ModelState.IsValid)
{
var userAuthenticated = UserInfo.AuthenticateUser(model.UserName, model.Password);
if (userAuthenticated)
{
var userInfo = UserInfo.FindByUserName(model.UserName);
//SERIALIZE AUTHENTICATED USER
var serializer = new JavaScriptSerializer();
var serializedUser = serializer.Serialize(userInfo);
var ticket = new FormsAuthenticationTicket(1, model.UserName, DateTime.Now, DateTime.Now.AddMinutes(30), false, serializedUser);
var hash = FormsAuthentication.Encrypt(ticket);
var authCookie = new HttpCookie(FormsAuthentication.FormsCookieName, hash) {Expires = ticket.Expiration};
Response.Cookies.Add(authCookie);
if (Url.IsLocalUrl(model.ReturnUrl) && model.ReturnUrl.Length > 1 && model.ReturnUrl.StartsWith("/") && !model.ReturnUrl.StartsWith("//") && !model.ReturnUrl.StartsWith("/\\"))
{
return Redirect(model.ReturnUrl);
}
var url = Url.Action("Index", "Course");
return Redirect(url);
}
ModelState.AddModelError("", "The user name or password provided is incorrect.");
}
This is working just fine in all browsers. I can login and access the secure pages in my app.
My client is requesting an android version of this app. So, I'm trying to figure out how to convert this app into an APK file. My first attempt is to create a simple index.html page with an iframe that targets the application. This works just fine in Firefox and IE 9. However, when accessing the index.html page that contains the iframe that points to the app via Chrome, I get past the login code above and the user gets redirected to the secure controller, but the secure controller has a custom attribute to make sure the user is authenticated:
public class RequiresAuthenticationAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (filterContext.HttpContext.User.Identity.IsAuthenticated) return;
if (filterContext.HttpContext.Request.Url == null) return;
var returnUrl = filterContext.HttpContext.Request.Url.AbsolutePath;
if (!filterContext.HttpContext.Request.Browser.IsMobileDevice)
{
filterContext.HttpContext.Response.Redirect(FormsAuthentication.LoginUrl + string.Format("?ReturnUrl={0}", returnUrl), true);
}
else
{
filterContext.HttpContext.Response.Redirect("/Home/Home", true);
}
}
}
My app is failing on: filterContext.HttpContext.User.Identity.IsAuthenticated. IsAuthenticated is always false, even though the user was authenticated in the code above.
Keep in mind this only happens when accessing the app via iframe in Chrome. If I access the app directly instead of via iframe, then everything works just fine.
Any ideas?
UPDATE:
My controller extends SecureController. In the constructor of SecureController I have the code that deserializes the user:
public SecureController()
{
var context = new HttpContextWrapper(System.Web.HttpContext.Current);
if (context.Request.Cookies[FormsAuthentication.FormsCookieName] != null)
{
var serializer = new JavaScriptSerializer();
var cookie = context.Request.Cookies[FormsAuthentication.FormsCookieName].Value;
var ticket = FormsAuthentication.Decrypt(cookie);
CurrentUser = serializer.Deserialize<UserInfo>(ticket.UserData);
}
else
{
CurrentUser = new UserInfo();
}
//if ajax request and session has expired, then force re-login
if (context.Request.IsAjaxRequest() && context.Request.IsAuthenticated == false)
{
context.Response.Clear();
context.Response.StatusCode = 401;
context.Response.Flush();
}
}
First, you should be deriving from AuthorizeAttribute, not an ActionFilterAttribute. Authorization attributes execute before the method is even called at a higher level of the pipeline, while ActionFilters execute much further down, and other attributes can execute before yours.
Secondly, you aren't showing the code you use to decrypt the ticket and set the IPrincipal and IIdentity. Since that's where the problem is, it's odd that you didn't include it.