0

HackThisSite フォーラムには、Omegle (omegle.com の匿名チャット クライアント) の動作を詳述するトピックがあります: https://www.hackthissite.org/forums/viewtopic.php?f=76&t=3783

それは少し時代遅れですが、それでもほとんど正確です。それを出発点として使用して、カスタムの Omegle クライアントに取り組んできました。最初はゲーム メーカーでプログラミングしましたが、Web アプリ サービスにより適していると考えた Javascript/AJAX (XSS の問題を回避するための小さな PHP バックエンドを使用) に切り替えました。

基本的に、Omegle の仕組みは、サーバーをポーリングし続けることです。ポーリングすると、前回のポーリング以降に発生したイベントのリストが返されます。これらのイベントには、「待機中」(ペアアップの場合)、「接続済み」(見知らぬ人への)、「gotMessage」(受信したメッセージを含むイベント)、「strangerDisconnected」(他のユーザーが切断したとき) などがあります。 .

私が言ったように、そのリンクは少し古くなっています。Omegle が追加した新しいものの 1 つは statusInfo と呼ばれるイベントです。これは、いくつかのサーバー情報 (現在動作しているサーバーのリストを含む) を持つ JSON オブジェクトを保持します。新しいイベントをチェックするたびに、動作中のサーバーの更新されたリストも取得されるため、サーバーがダウンした場合にサーバーをホップできます。

これはすべてうまくいき、私のカスタム クライアントはうまく動作する場合もありますが、バグがあります。サーバーにイベントをポーリングするときに、サーバーが応答しないことを決定することがよくあります。確認応答やステータス コードを返信することさえないため、AJAX 要求はそこに留まり、応答が返ってこないのを待ちます。奇妙なことに、これが発生した場合、サーバーをホップしても、多くの場合、役に立ちません。いずれにせよ、サーバーに関係なく、次のリクエストでハングアップし、ランダムに再び作業を開始することを決定します。そして、これはすべて完全に恣意的なように思えます。私が知る限り、2 つのカテゴリの間に共通のスレッドはなく、完全に機能する場合もあれば、残りの場合はハングする場合もあります。

さらに奇妙なことに、このようなハングが発生しているときに切断しようとすると (ユーザー ID を投稿して server.omegle.com/disconnect に要求を送信するだけです)、Omegle は「Internal Server Error」メッセージを返します。イベントリクエストにハングアップがない場合、切断するとそれは行われません。

あなたを私のクライアントにリンクしたいのですが、私は現在、ほとんど制御できないファイアウォールの背後にいるので、代わりにここにコードを投稿する必要があります...それは2つの小さなファイルと1つの大きなファイルだけです.とにかく、誰かがそれをテストできることを願っていますか?

これ以上苦労することなく、これが私がクライアントに使用している HTML/Javascript 全体です (ライブラリは使用されていません。すべてゼロからコーディングされています)。私はあなたのためにそれをすべてコメントするために入ったところです。うまくいけば、それは明らかです。

<style>
.error { color:#ff0000; }
.them { color: #ff0000; }
.you { color:#0000ff; }
.typer { color:#555555; font-weight:bold; font-size:11pt; }
</style>

<script>

/* Cross-platform XMLHttpRequest function */
function Request() {
  if (window.XMLHttpRequest ) { return new XMLHttpRequest(); }
  else if (window.ActiveXObject) {
    try {
      return new ActiveXObject("Msxml2.XMLHTTP");
    }
    catch (e) {
      try {
        return new ActiveXObject("Microsoft.XMLHTTP");
      }
      catch (e) {
        return false;
      }
    }
  }
}

/* Common array shuffling function used to shuffle the list of servers */
function shuffle(a) {
  var m = a.length, t, i;

  // While there remain elements to shuffle...
  while (m) {

    // Pick a remaining element...
    i = Math.floor(Math.random() * m--);

    // And swap it with the current element.
    t = a[m];
    a[m] = a[i];
    a[i] = t;
  }

  return a;
}

/* A general-purpose handler for the XMLHttpRequests, which simply checks for a "completed" state and then calls the associated handler. I plan on making this more
   robust once the overall system is working at all. */
function HandleXHR() {
  if (this.readyState==4) {
    this.handler(this.responseText);
  }
}

server=null;
servs=null;

/* Whenever a statusInfo message is received, it includes a list of working servers. This code, almost identical to Omegle's own, modifies our own list of servers
   to include all of those (and remove no-longer-working ones) without changing the relative order of the current servers on the list */
function updateServers(list) {
  list=shuffle(list);
  for (i=0; i<list.length; ++i) {
    if (servs.indexOf(list[i])<0) {
      servs.unshift(list[i]);
    }
  }

  for (i=0; i<servs.length; ++i) {
    if (list.indexOf(servs[i])<0) {
      servs.splice(i--, 1);
    }
  }

  server=servs[0];

}

typing=false;

/* Initiate looking for a connection; this requests a user ID from the server, which itself is randomly chosen from the list of servers. This is actually what Omegle's
   own code does--it shuffles the server list around for uniform usage. */
function Connect(what) {
  typing=false;
  what=JSON.parse(what);
  servs=shuffle(what.servers);
  server=servs[0];

  req=Request();
  where="http://"+server+"/start?rcs=1&spid=";
  req.open("GET", "getpage.php?url="+escape(where));
  req.handler=GotID;
  req.onreadystatechange=HandleXHR;
  req.send(null);
}

id=null;
eventwatch=null;

/* When a connection is made and we have a user ID, start polling for events immediately */
function GotID(what) {
  id=what.split('"')[1];
  eventwatch=setTimeout(GetEvents, 1);
}

/* Initiate the poll to the server for any recent events */
function GetEvents() {
  if (id==null) { return false; }

  where="http://"+server+"/events";  
  req=Request();
  req.open("POST", "getposted.php?url="+escape(where));
  req.setRequestHeader("Content-type", "application/x-www-form-urlencoded");

  req.handler=ParseEvents;
  req.onreadystatechange=HandleXHR;

  req.send("id="+escape(id));
}

/* The function that parses all the events when they've been received from a poll */
attempts=0;
function ParseEvents(what) {

  spot=document.getElementById("codespot");

  try {
    what=JSON.parse(what);
    attempts=0;
  }

  /* If the messages couldn't be parsed, i.e. the server didn't return anything or returned malformed JSON (or an error),
     hop servers and try again, up to 3 times before giving up */
  catch (e) {
    attempts++;

    /* Move the first server on the list to the end and pick the next server */
    temp=servs.shift();
    servs.push(temp);
    server=servs[0];

    if (attempts>=3) {
      spot.innerHTML+="<b class='error'>Error: "+e.message+"</b><br />";
      Disconnect();
      return false;
    }

    eventwatch=setTimeout(GetEvents, 2500);
    return false;
  }

  /* Process each message */
  for (p in what) {
    code=what[p][0];

    /* Connected event */
    if (code=="connected") {
      spot.innerHTML+="<b>Connected!</b><br />";
      document.getElementById("waiter").innerHTML="";
    }

    /* Message reception */
    else if (code=="gotMessage") { spot.innerHTML+="<b class='them'>Stranger:</b> "+what[p][1]+"<br />"; }

    /* The other user disconnected, so stop checking for events and set your user ID to null (meaning no connection) */
    else if (code=="strangerDisconnected") { typing=false; id=null; spot.innerHTML+="<b>Stranger disconnected</b><br />"; window.clearTimeout(eventwatch); }

    /* Process the statusInfo events by updating the server list */
    else if (code=="statusInfo") {
      updateServers(what[p][1].servers);
    }

    /* These are only used for Omegle logs, which I'm not implementing, so ignore them */
    else if (code=="identDigests") { /* Ignore these for now */ }

    /* Change stranger-typing status */
    else if (code=="typing") { typing=!typing; }
    else if (code=="stoppedTyping") { typing=false; }

    /* Before a connection is made, let the user know you're waiting for one */
    else if (code=="waiting") {
      document.getElementById("waiter").innerHTML="Looking for a stranger...";
    }

    /* If all else fails, we don't know what this message is, so output it for debugging purposes--hasn't happened in all my tests yet */
    else { spot.innerHTML+="Didn't understand: "+code+"<br />"; }
  }

  /* Update the "is typing" display and set a timeout for the next event poll */
  document.getElementById("typer").innerHTML=typing ? "Stranger is typing..." : "";
  eventwatch=setTimeout(GetEvents, 2500);
}

/* The function that attempts to disconnect from the conversation */
function Disconnect() {
  where="http://"+server+"/disconnect?id="+id;

  req=Request();
  req.open("POST", "getposted.php?url="+escape(where));
  req.setRequestHeader("Content-type", "application/x-www-form-urlencoded");

  req.handler=Disconnected;
  req.onreadystatechange=HandleXHR;

  req.send("id="+escape(id));
}

/* The function to send a message */
function Send(place) {
  if (id==null) { return false; }
  what=place.value;
  place.disabled=true;

  where="http://"+server+"/send";

  req=Request();
  req.open("POST", "getposted.php?url="+escape(where));
  req.setRequestHeader("Content-type", "application/x-www-form-urlencoded");

  req.handler=Sent;
  req.onreadystatechange=HandleXHR;

  req.send("id="+escape(id)+"&msg="+escape(what));
}

/* The function to handle the display when a message you've typed has been sent */
function Sent(what) {
  if (id==null) { return false; }
  document.getElementById("codespot").innerHTML+="<b class='you'>You:</b> "+document.main.mess.value+"<br />";
  document.main.mess.disabled=false;
  document.main.mess.value="";
}

/* The function to handle cleanup once you've disconnected */
function Disconnected(what) {
  typing=false;
  id=null;
  window.clearTimeout(eventwatch);
  document.getElementById("codespot").innerHTML+="<b>Disconnected";
  if (what.substr(0, 3)!="win") { document.getElementById("codespot").innerHTML+=" -- "+what; }
  document.getElementById("codespot").innerHTML+="</b><br />";
}

/* The function to initiate the requests to get the list of active Omegle servers */
function GetServer() {
  req=Request();
  where="http://omegle.com/status";
  req.open("GET", "getpage.php?url="+escape(where));
  req.handler=Connect;
  req.onreadystatechange=HandleXHR;
  req.send(null);
}

</script>

<!-- The chat area -->
<div id="waiter" class="typer"></div>
<div id="codespot"></div>
<div id="typer" class="typer"></div><br />

<!-- The form where you connect, disconnect, and send messages from -->
<form name="main" onSubmit="Send(document.main.mess); return false"><input type="button" value="Connect" onClick="GetServer()" /><input type='text' name='mess' /><input type='submit' value='Send' />
<input type="button" value="Disconnect" onClick="Disconnect()" />

また、バックエンドの PHP スクリプト getpage.php および getposted.php は、単に cURL を使用して Omegle から応答を取得し (別のドメインにあるにもかかわらず)、それらを直接エコーすることで、XHR がドメイン外のページにアクセスできるようにします。

ストールが時々発生する理由を理解するのを手伝ってくれる人はいますか?

getposted.php および getpage.php コードの単純なコードが必要な場合は、次のようになります。

getposted.php:

<?php
  set_time_limit(60);
  $curl=curl_init();
  curl_setopt($curl, CURLOPT_URL, $_GET["url"]);
  curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); // Return value instead of outputting
  curl_setopt($curl,CURLOPT_POST, count($_POST));
  curl_setopt($curl,CURLOPT_POSTFIELDS, http_build_query($_POST, '', '&'));

  $all=curl_exec($curl);
  curl_close($curl);
  echo $all;
?>

getpage.php

<?php
  set_time_limit(60);
  $curl=curl_init();
  curl_setopt($curl, CURLOPT_URL, $_GET["url"]);
  curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); // Return value instead of outputting

  $all=curl_exec($curl);
  curl_close($curl);
  echo $all;
?>
4

0 に答える 0