Let's reverse-engineer Omegle. PROPERLY! ======================================== I didn't manage to find a proper, detailed (and up-to-date) reverse-engineerment of Omegle's text chat protocol on the interwebs, so here, have one! The responses are beautified and the query strings split up and URI-decoded for readability. Note that "query string" refers to parameters encoded into the URL and "form data" to parameters in the POST body which don't have to be URI-encoded. TODO: * Find out how college authorization works * Find out how WebRTC video streaming works * Generally phrase things better __Used Request Headers__ ``` Accept: application/json Accept-Encoding: gzip,deflate Accept-Language: en-US;q=0.6,en;q=0.4 Connection: keep-alive DNT: 1 Host: front9.omegle.com Origin: http://www.omegle.com Referer: http://www.omegle.com/ User-Agent: Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2062.94 Safari/537.36 ``` Note that the headers `X-Requested-With` and `X-Request` are deliberately removed from requests by the JavaScript. Status ------ Pro-Tip: Fetch this first and then use one of the servers/subs listed for future connections (you can just connect to the main server here). Also, you should switch to another one if the current isn't listed anymore. `GET http://[server].omegle.com/status` __Query String__ * `nocache = 0.4695589093025774` (optional, random nonce to prevent cached responses from being sent) * `randid = CHPZGFFW` (optional, see section "Start") __Response__ ```javascript { "count": 20840, // connection count, people say it's faked "force_unmon": true, // your IP was banned, see "Getting b&" "antinudeservers": [ "waw3.omegle.com", "waw2.omegle.com", "waw1.omegle.com" ], "antinudepercent": 1.0, "spyQueueTime": 0.0, // if spyQueueTime is larger, there are more spies than // spyees online, which the client uses to suggest a mode "spyeeQueueTime": 2.173300027847, "timestamp": 1409233880.7561221, "servers": [ "front5.omegle.com", "front1.omegle.com", "front2.omegle.com", "front9.omegle.com", "front6.omegle.com", "front7.omegle.com", "front8.omegle.com", "front4.omegle.com", "front3.omegle.com" ] } ``` Start ----- This actually starts the chat and gets us our client ID. If you want to start a question/spy chat, send `wantsspy = 1` for spyee mode and `ask = blah` for spyer mode. `POST http://[server].omegle.com/start` __Query String__ * `rcs = 1` * `firstevents = 1` * `m = 1` (imitate a mobile connection, shouldn't really matter) * `randid = CHPZGFFW` (this is really just a random string containing 2-9 and A-Z) * `spid =` (some kind of ID from Adobe Stratus, never used though) * `group = unmon` (optional, join the unmonitored section instead) * `lang = en` (optional, two-char language code) * `topics = ["asdf", "test", ...]` (in default mode only) Spyer/Spyee * `wantsspy = 1` (for spyee mode) * `ask = blah?` (for spyer mode) * `cansavequestion = 1` (optional, in spyer mode only, Omegle may reuse your question) Camera Chat * `webrtc = 1` (for camera chat) * `camera = ` (probably just a flag, was " " for me in camera chat) College Chat * `college = ?` (optional, TODO) * `college_auth = ?` (optional, TODO) * `any_college = 1` (optional, TODO) __Response__ ```javascript { "events": [ // ...see section "Events"... ], "clientID": "central2:k0m4akq5ry4ytvklsrs2jmtsjkpbkh" // needed for all subsequent requests } ``` Events ------ This one uses long polling, which means that the server will be blocking the connection until an event happens. You can handle this with some async magic and long timeouts. `POST http://[server].omegle.com/events` __Form Data__ * `id = central2:k0m4akq5ry4ytvklsrs2jmtsjkpbkh` __Response__ ```javascript [ // see below ["method", "arg"], ["method", "arg", "arg"], // ... ] ``` ### Status events * `["waiting"]` (the server is searching for strangers) * `["connected"]` (you can start sending messages now) * `["statusInfo", {...}]` (see section "Status") * `["count", 20900]` (update the connection/online count, never encountered this one but it's in the source) ### Notifications * `["commonLikes", ["a", "b", ...]]` (the shared topics from the ones you've passed) * `["partnerCollege", "blah"]` (chat partner goes to this college) * `["serverMessage", "blah"]` (most likely `You both speak the same language.`) * `["recaptchaRequired", "ChALlEnGe"]` (see section "ReCAPTCHAs") * `["recaptchaRejected", "ChALlEnGe"]` * `["identDigests", "a,b,c"]` (probably only used for sharing logs) ### Error events (disconnects you) * `["error", "blah!"]` (general error message) * `["connectionDied"]` (some technical error) * `["antinudeBanned"]` (see section "Getting b8") ### Chat events * `["typing"]` (the stranger started typing) * `["stoppedTyping"]` (...stopped typing) * `["gotMessage", "blah"]` (...sent a message) * `["strangerDisconnected"]` (...decided to disconnect) ### In spyee mode * `["question", "blah?"]` (the question you'll discuss with the stranger) ### In spyer mode * `["question", "blah?"]` (your question) * `["spyTyping", "Stranger <1/2>"]` (Stranger 1/2 started typing) * `["spyStoppedTyping", "Stranger <1/2>"]` (...stopped typing) * `["spyMessage", "Stranger <1/2>", "blah"]` (...sent a message) * `["spyDisconnected", "Stranger <1/2>"]` (...decided to disconnect) ### In camera chat * `["icecandidate", "blah"]` (see section "Connecting to the WebRTC peer") * `["rtccall", "blah"]` (TODO) * `["rtcpeerdescription"]` (see section "Send WebRTC Peer description") Send messages ------------- I'm not sure about the Unicode support, but it should work in most cases. `POST http://[server].omegle.com/send` __Form Data__ * `msg = lol` * `id = central2:k0m4akq5ry4ytvklsrs2jmtsjkpbkh` __Response__ ``` win ``` Set your "typing" status ------------------------ The server may detect clients that don't send these. `POST http://[server].omegle.com/typing` `POST http://[server].omegle.com/stoppedtyping` __Form Data__ * `id = central2:k0m4akq5ry4ytvklsrs2jmtsjkpbkh` __Response__ ``` win ``` Stop looking for common topics ------------------------------ If you've passed `topics` to `/start`, the server will send the `waiting` event and then search for people with the same topics until the client sends this. Use it after some time to stop the running search, ignore the topics and continue with connecting. `POST http://[server].omegle.com/stoplookingforcommonlikes` __Form Data__ * `id = central2:k0m4akq5ry4ytvklsrs2jmtsjkpbkh` __Response__ ``` win ``` Disconnect from the current chat -------------------------------- Simple as that. Always use this to end sessions gracefully, unless noted beneath events. This can also be used to disconnect both strangers in the spyer mode. `POST http://[server].omegle.com/disconnect` __Form Data__ * `id = central2:k0m4akq5ry4ytvklsrs2jmtsjkpbkh` __Response__ ``` win ``` Send WebRTC Peer description ---------------------------- TODO Send WebRTC ICE candidates -------------------------- This is what you should do when your RTCPeerConnection fires the `onicecandidate` event. Basically, the Omegle client stores all received candidates in a list and then sets a 300ms timeout for more candidates to get pushed onto the list after which it sends the list to the server and clears it. `POST http://[server].omegle.com/icecandidate` __Form Data__ * `id = central2:k0m4akq5ry4ytvklsrs2jmtsjkpbkh` * `candidate = %7B...%7D` (url-encoded JSON representation of a candidate) * `candidate = ...` (multiple times) __Response__ ``` win ``` Connecting to the WebRTC peer ----------------------------- TODO ReCAPTCHAS ---------- If you run into an `recaptchaRequired` event, you must prove that you're a human by fetching the captcha using the URL-encoded passed code from `http://www.google.com/recaptcha/api/image?c=[challenge]` and sending the answer like this. Note that I haven't tried this yet. `POST http://[server].omegle.com/recaptcha` __Form Data__ * `id = central2:k0m4akq5ry4ytvklsrs2jmtsjkpbkh` * `challenge = [challenge]` * `response = [answer]` Getting b& ---------- If you got an `antinudeBanned` event, the modarating system banned you from the monitored section for "bad behaviour". From now on, the server status object (see section "Status") will have `force_unmon` set to `true`. You can switch to the unmonitored section by passing `group = unmon` to `/start`. They won't give you this mercy if you got your IP banned because of too rapid connecting or advertising, but bans don't last forever anyway. Sharing logs ------------ To upload your logs to Omegles server, use this. Pro-Tip: You can actually pass any arbitrary text as the log. It's a JSON-encoded list containing lists that contain the strings. Oh, and HTML injection doesn't work, I tried. These are the triggers that add some formatting: * `["*"]` (smaller, bold font, gray) * `["* disconnected"]` (as above) * `["Question to discuss:", "*"]` (blue question box) * `["Stranger:", "*"]` (large font, first item is red) * `["Stranger 1:", "*"]` (as above) * `["Stranger 2:", "*"]` (large font, first item is blue) * `["You:", "*"]` (as above) * `["*", "*"]` (normal font, first item is bold) `POST http://logs.omegle.com/generate` __Form Data__ * `logs = [["You:", "blah"], ...]` (JSON table of the plaintext chat, split in lines) * `randid = CHPZGFFW` (Your random ID) * `topics = ["asdf", "test", ...]` (optional, the shared topics) * `identdigests = blah,blah,blah` (the most recent data from the `identDigests` event) * `host = 1` Response: 302 Found, the `Location` header contains the log link in the format `http://logs.omegle.com/[id]`. The log image can be fetched from `http://l.omegle.com/[id].png`.