konsumer / tindercred

display credentials for facebook authentication on tinder
2 stars 5 forks source link

Won't change html to reflect tokens #1

Closed mayeaux closed 7 years ago

mayeaux commented 8 years ago

I'm not having an issue getting my token, but someone else said they couldn't get this app to work and I checked it out. Think it's a great idea, I checked the source too and it looks like it should work but after you hit the page after a successful authentication (which shows a warning in the html), it just sits there and the markup isn't changed to the token.

May be worth looking into if you have a minute, otherwise I may try and debug it next weekend.

konsumer commented 8 years ago

I noticed this too. When I have more time I'd be happy to look into it, but in the meantime, if you figure it out, I'd happily accept a PR. I think it might not be triggering the load event, but I'm really not sure.

mayeaux commented 8 years ago

Okay sure, we'll see if I get some time this week. May have to wait until next weekend. I got my token no problem but some poor guy has posted on nearly every issue on /tinderjs about his woes, so maybe I'll help him get this app settled out. Cheers.

cruzw commented 8 years ago

Couldn't get it to work either, seems promising though.

mayeaux commented 8 years ago

Yeah I've got a couple minutes here before I start the day, I'll see if I can get it up.

Another nice implementation is done by the ruby module, where you provide your credentials and then have a script fetch your token for you, although I haven't checked out how they do it in source yet that is probably the nicest programmatic option atm: https://github.com/jvenezia/tinderbot

cruzw commented 8 years ago

https://github.com/jvenezia/tinderbot/blob/master/lib/tinderbot/facebook.rb

seems to be a ruby CLI that boots up a browser and logs in for ya, and then returns the token from the URL immediately. wouldn't be to difficult to implement in nightmare/phantom as a CLI, perhaps as a heroku web-service, might tackle it today.

mayeaux commented 8 years ago

Baha @gcwelborn check it out: https://www.npmjs.com/package/tinder we got the tinder package name.

Also, I've found out what the issue is. The event listener is returning an error URL for the URL:

https://www.facebook.com/login.php?skip_api_login=1&api_key=464891386855067&signed_next=1&next=https%3A%2F%2Fwww.facebook.com%2Fv2.0%2Fdialog%2Foauth%3Fredirect_uri%3Dhttps%253A%252F%252Fwww.facebook.com%252Fconnect%252Flogin_success.html%26scope%3Dbasic_info%252Cemail%252Cpublic_profile%252Cuser_about_me%252Cuser_activities%252Cuser_birthday%252Cuser_education_history%252Cuser_friends%252Cuser_interests%252Cuser_likes%252Cuser_location%252Cuser_photos%252Cuser_relationship_details%26response_type%3Dtoken%26client_id%3D464891386855067%26ret%3Dlogin&cancel_url=https%3A%2F%2Fwww.facebook.com%2Fconnect%2Flogin_success.html%3Ferror%3Daccess_denied%26error_code%3D200%26error_description%3DPermissions%2Berror%26error_reason%3Duser_denied%23_%3D_&display=page""

So it's trying to hit that URL above with the regexp and failing to find a match (the regexp is returning null). I'm going to check which other events we can listen to, because visually I can see the proper URL load, so we should be able to grab it without too much of an issue.

konsumer commented 8 years ago

It looks like the ruby lib is using Watir. This might be a nice direction (a virtual browser testing lib) so the dumb real browser-context isn't needed. Maybe zombie.js?

konsumer commented 8 years ago

I think maybe I only tested with an already ok'd facebook app. I will work on using zombie with both types.

mayeaux commented 8 years ago

@konsumer I lied. That 'error' is given when the page is loaded for the first time no matter what, it's just that the 'load' eventListener is listening to the wrong event, it should listen for when the second page is opened, not the original one. So, if for example I navigate to Facebook.com from the NW.js window, and am effectively 'logged in', the module works the next time I load it because the initial load gives a token without requiring a login process, that's probably where you got hung up, you were likely already logged in as a Facebook user on nw.js when you were writing it.

konsumer commented 8 years ago

@mrmayfield Yeh, makes sense. I think I'm just going to switch directions and make it headless. That's really what I wanted anyway, and it seems like the way others are doing it (like that ruby project) is to use a fake browser, which I can totally do. I made this as a quick hack, but it felt a little dumb using a real browser context in NWjs.

mayeaux commented 8 years ago

So yes, the way to get this to work with the current implementation is to get the document URL when the second page (after posting login credentials) is loaded. My nw.js skills are a little sketchy and I don't see any events other than .unload that might offer us an event to listen to. Would be nice if we could do something like loginWindow.onUrlChange.addEventListener() , but I don't see something like that from a quick scan of the docs.

mayeaux commented 8 years ago

Yeah no problem, I actually really like the implementation. I'm maintaining the Tinder desktop browser and we use basically the same workflow to authenticate the tinderjs client locally. Although yes, headless is probably the gold standard here, it will require people to have at least a modicum of development skills to pass the variables to their program and run it, but then again if you're after these tokens in the first place you probably have development skills & it takes a bit of dev knowledge to get nw.js running anyways.

konsumer commented 8 years ago

you could use a counter or better check for token, but again I don't really like that solution. I should maybe rename this to headless_facebook_token, or something, too, since it isn't really about tinder at all. I've just about got some code to do it with zombie finished.

mayeaux commented 8 years ago

Okay cool, and I've actually got a fix for this based on the suggestions above. It's a little ugly but should work, should be up in a min or two as well.

mayeaux commented 8 years ago

Lol well I've code that should be working, but I'm having a helluva time binding to the 'submit' event of the the login form

everytime I run

document.getElementById('login_form') from within the load eventListener, it always returns null :\

konsumer commented 8 years ago

Yeh, I ran into issues with 2FA. Hmm.

mayeaux commented 8 years ago

Can you push your source? Wouldn't mind taking a look at it, although I won't have a chance to do anything until the evening.

konsumer commented 8 years ago

I don't think this direction will work. I am doing something similar, but a bit different here. Also, I made this, if you just need your user token. It's a totally static page (view source) that will get it for you.

konsumer commented 8 years ago

To minimize maintenance overhead I've just included my jstinder lib, which has a function that does the same thing, and it seems to work ok.

mayeaux commented 8 years ago

Just tried it , didnt work for me :\

My method (in the PR) is working but relatively ugly. If you could help me target that form ( document.getElementById('login_form') ) , I can make it super clean. :)

mayeaux commented 8 years ago

Did you get any progress on the headless implementation? Maybe you want to push your work in progress? I could definitely use that for some bots I'm planning to make, I'll probably make it myself this weekend if you don't have a chance

mayeaux commented 8 years ago

Okay I got it working :) I have to polish it up but I'm going to create a module for it and publish it to npm tomorrow :)

konsumer commented 8 years ago

As I said, I don't think headless is going to be so great, as there are several steps in auth (especially with 2-factor.) I don't really like recursive setTimeout loops, either. If I have some time, maybe I can get something working, but I'm surprised it isn't working for you. I got it working logged in, not logged in, and logged in, but with app permissions removed. I need to investigate more, I think. I'm interested to see what you did that works.

mayeaux commented 8 years ago

Oops, sorry! I mean to say that I got the headless browser implementation working. This tindercred still works with me with that setTimeout design which is somewhat ugly but effective lol, maybe later we'll have a bit of time to debug why I can't grab that element via nw.js

konsumer commented 8 years ago

it works with 2fa?

mayeaux commented 8 years ago

Nope, not with 2FA. Not sure how it could be done but a Facebook app would probably have to be made and have a special token generated for it. For it to scale to support any user (without manually adding someone to the app as a developer) it would probably have to be passed by Facebook inspection which is a PITA. What's your thoughts?

konsumer commented 8 years ago

I think 2fa doesn't require any more, though, it's just more forms. After the initial user-login, it redirects to the 2fa page before hitting the redirect_url (with the token in the url.) I dunno if headless is really the way to go, though, especially in an app that can show webviews (like electron or nwjs app.) Like maybe it's better to get the load event stuff working, and figure out why it's not finding the token in url.

mayeaux commented 8 years ago

Sorry, I think we're thinking down different lines. With 2FA you still require manual input (I'm not sure if it sends a text or if it's with something like Google Authenticator) so it can't be 100% programmatic. I want this to copy Ruby's tinderbot implementation of programatically getting a user's token for tinder and also profile ID. I've noticed that when I'm programatically going through recommendations, sometimes I am prevented from hitting the Tinder API more until I refresh my token with Tinder, this could be a way around that. I don't think headless browser scraping will support 2FA, but in all honesty, people shouldn't be using these kind of experimental tools with their real Facebook anyways (I had functionality frozen because of playing around with Tinder tokens I believe). Just making a burner Facebook account specifically for Tinder which doesn't require 2FA is the better approach imo.

konsumer commented 8 years ago

Yeh, totally. I'm trying to create a lib for a custom tinder-client, but I'm happy to help out with your headless thing, if you put the code somewhere.

mayeaux commented 8 years ago

Here's what I have so far: https://github.com/tinderjs/tindermatch/blob/master/getTokenAndProfileScript.js

Obviously it needs a touching up and to return the values instead of logging them. Also, it will end up being its own package published to npm ( tinderauth ) , but it is working. A lot of awesome but unmaintained tinder + js projects I am bringing under the umbrella of https://github.com/tinderjs and working on them with a few other devs if you'd like to join us :)

And I checked a couple of your other modules out and see you've done some Powerball related projects in the past. I'm actually working for a startup right now based out of SF that let's you buy Powerball tickets with your cell phone :) Might be an interesting opportunity if you want to check it out ( http://www.autolotto.com ) . We are built with Node/Express backend and iOS/Android clients.

mayeaux commented 8 years ago

https://github.com/tinderjs/tinderauth

Okay it's up and working! A little laggy, I think there's a wait value of zombieJS that is delaying it a bit, but it is functonal

konsumer commented 8 years ago

This worked for me. It returns a promise that properly handles errors and resolves to the token.

import Browser from 'zombie'

const fb_url = 'https://www.facebook.com/dialog/oauth?client_id=464891386855067&redirect_uri=https://www.facebook.com/connect/login_success.html&scope=basic_info,email,public_profile,user_about_me,user_activities,user_birthday,user_education_history,user_friends,user_interests,user_likes,user_location,user_photos,user_relationship_details&response_type=token'

function fbtoken(email, password){
  Browser.waitDuration = '10s'
  const browser = new Browser()
  const re = /#access_token=(.+)&/
  let token = null
  const i = setInterval(() => {
    if ((token = re.exec(browser.url)) !== null) {
      clearInterval(i)
    }
  }, 0)
  return browser.visit(fb_url)
    .then(() => {
      return browser
        .fill('#email', email)
        .fill('#pass', password)
        .pressButton('#loginbutton')
    })
    .then(() => {
      clearInterval(i)
      if (token && token[1]){
        return token[1]
      }
    })
}