{"id":22783846,"url":"https://github.com/greg-kennedy/hasbropbemproxy","last_synced_at":"2025-04-30T10:25:10.204Z","repository":{"id":86779569,"uuid":"410457948","full_name":"greg-kennedy/HasbroPBEMProxy","owner":"greg-kennedy","description":"Server emulator for the Hasbro Em@il Games clients","archived":false,"fork":false,"pushed_at":"2022-07-12T03:28:33.000Z","size":182,"stargazers_count":5,"open_issues_count":0,"forks_count":2,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-04-30T10:24:59.366Z","etag":null,"topics":["http-proxy","server-emulator","x-com"],"latest_commit_sha":null,"homepage":"","language":"HTML","has_issues":false,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"cc0-1.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/greg-kennedy.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-09-26T05:23:56.000Z","updated_at":"2024-06-11T10:43:08.000Z","dependencies_parsed_at":null,"dependency_job_id":"ebd99a1d-4a5d-41f8-9766-b26add1997c1","html_url":"https://github.com/greg-kennedy/HasbroPBEMProxy","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/greg-kennedy%2FHasbroPBEMProxy","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/greg-kennedy%2FHasbroPBEMProxy/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/greg-kennedy%2FHasbroPBEMProxy/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/greg-kennedy%2FHasbroPBEMProxy/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/greg-kennedy","download_url":"https://codeload.github.com/greg-kennedy/HasbroPBEMProxy/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":251684273,"owners_count":21627104,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["http-proxy","server-emulator","x-com"],"created_at":"2024-12-11T22:09:36.740Z","updated_at":"2025-04-30T10:25:10.177Z","avatar_url":"https://github.com/greg-kennedy.png","language":"HTML","funding_links":[],"categories":[],"sub_categories":[],"readme":"# HasbroPBEMProxy\n_Greg Kennedy, 2021_\n\nServer emulator for the Hasbro Em@il Games clients\n\n## About\nIn 1999 Hasbro launched a series of games under the \"Em@il Games\" banner, allowing users with limited internet connections to play a handful of turn-based games using their existing email address.  A player would begin a new game from the app on their computer, make moves, and submit them to Hasbro's servers by clicking a button.  Hasbro would then send an email to the opponent with a .bin snapshot of the gamestate and an \"it's your turn!\" message.  From there the opponent would check their email, see an attached savegame, double-click to launch and make moves, and submit their updates back to the first opponent (again, through Hasbro's servers).\n\nThe servers folded in 2001.  This rendered the games nearly unplayable, except for certain [workarounds](http://worldofstuart.excellentcontent.com/excom.htm) involving retrieving the savegame from a temp folder and passing it around manually.  Most games in the series were board game conversions and not very interesting, but there was a lesser-known X-Com tactical game that still may be worth playing today.\n\n**This project is an attempt to revive the game servers to enable easier exchange of the savegames** without needing to dig around in folders anywhere.  This is done by using the \"Proxy Server\" settings in a game, like so:\n\n![Proxy config dialog box](proxy.png)\n\nA Proxy Server is intended to act as a middleman for HTTP connections: instead of sending your requests to a remote website directly, you instead pass them to the proxy server, which forwards the request (and response) on your behalf.  This is helpful for privacy, website allow/deny listing, etc.  The Hasbro games support a proxy, but do not use HTTPS (SSL) for the connection.  It is thus very easy to write our own bogus proxy service that captures the request and instead serves its own response.  By faking the response as though it is an actual Hasbro server, the proxy can capture and exchange gamestates, while the application thinks it's just gotten off the phone with Hasbro.\n\n## Supported Games\nThe following games are currently supported by the proxy:\n\n* Email X-Com (aka EX-COM aka X-Com: First Alien Encounter).\n* Email NASCAR\n* Email NFL Football\n* Email Clue / Cluedo\n* Email Scrabble\n* Email Battleship\n\nI am interested in other games in the Em@il Games series, and may add support for those in the future.\n\n## Details\nSubmitting a turn involves sending a specially crafted HTTP request to a formatted URL at one of two hardcoded IP addresses.  For X-Com, the primary IP is `128.11.41.76`, and if any part of the request fails it makes another identical attempt at `128.11.41.77` instead.\n\nThe URL format is:\nhttp://128.11.41.76:80/1632633091/776.htm\nwhere the first path parameter is a `time32_t` Unix timestamp, and the second is milliseconds.\n\nAn example web request made by the client looks like this:\n```\nGET http://128.11.41.76:80/1632635052/35.htm HTTP/1.0\nUser-Agent: Hasbro/2.0 (compatible; EmailGame 57.57; Windows 95)\nHost: 128.11.41.76:80\nPragma: no-cache\nCookie: HasbroCookieVR1=AAAAcAAAOTkAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAGFQCI4A7v8MAAAAAQAAAAAgoeADWIH3dgAABClWPhf/qcEZSyHB86VbcS7Ek5ZEfhLS8NLrJk1wYDcO5UJsk7/nJrdq29WNak4h5NjzzSVZB8yoi342XNbakHBXE+DQ8GRfNILH1f0gSXirwo1eRW6TwOsWO2adtt0CMViPrEf/J1J7osn2HURrmMPuEzpgjrXlCSRahKfX/yodBOHM9RtHcpzC6Rg9ZIm44wYzzoSu1QMpUHikz/MfSnSaxegVPGOQt+MLMlyGpd0BKA8D5873JklwncTvHz9qm7rhADXMhrDbAStWfqbN/iFIdZzD7RdCapK14Q0wXoi72QMugQDl0PklS3aaxu0IQWifvOcCN/KIstkALVR7qNP8I05znsHyGUBplLPlDz5girneBSzH/uvS+yJNdJnI8xFDbpm+5Rw58Iq03wcvWoCq0fklTHKgz/EbRm6WseoRPGKMv9oHMkH96dT9IE96p8rxEUVslsDrHjv2jLbdDDFYh6zX/SdSeqLN9x1EbJjP7hMqZI614gkwWISv0v8qVHqhyvUcRnCTkod1RAP9mNMKJCzpz65lW2A7wbWXcjgd/+2PelNn4LjiCTJdgKnYA4osPqXO8yBLdpvG7xY9ZZG45wynX4ey2wIpVn2ky/gjTnOawO4VRWmcveQfPV+KRVpBLFV4p9L/Ikl1ncTmGENuky7kDjVjibDYBC9Xf6rQ+iVKdZzB8BdFa4a15g0Q4ciz3AMuVYap0PokT3CfyvUa0W2VvOYQO2OLttgGLV2BrNf8J0p3rsHyCU1tlNNoUzpji7XcADBbgavW/iZNfKFY8hxHapfC7RI5Yo202Qg3WIOu1/4pWXmwzPQfohDaweoXPGeKt+IKMlmCrdT7KMN7o873HkVymcDtFD9gj77iCjFfhaDcADtYe6Z9dl1IcZzD7hM+ZZW54Ao0X4KvSgAqUXilzPMgS3Gbxu4WOWuRuOAMO1SHntgCITYRyayTUmQR8bXuEiYPkKpa36b5IR0VzOOaGMG5kZ2Y5jtvQyOOpVzagw0lz/cOC+A+YLBkHpxFEtkgFUXQH3isjtU8WG2PoGPWefEpBX7oiOHOMmVcqj79MBRKqJTPJg2NV7YMGThXqLz37vCYOJbe4AwydZyg7kY4RIqr46+Fgma91C6M5Emb3sUsa0K5kM8mHXSjivEoAXhTiv3UD2aoFVIOjNXZPPNQvYTTJptd4suwmedrtZUDOtJ32fOkjXJbqUN31sX8k78H0GZPNB1r9Dkph75VDEVKWAH239E5+2pKYBc4g1lwqcL774a9rwsi2Q/BPRZPoJmRSH8WzeSYTA9jVI3m387F7AVAa5O75gowW3ex2gIswHCn0vwiS4Wbxu/qSWtgteT6N2CNStsEKK98rCn5JrV3mDLyHrRunkzgBcppgUDVDtpXyctHz40FE/OknjZjG/rMi3QYYnkAAAACAAAACVBsYXllciAxAAAAABRwbGF5ZXIxQGV4YW1wbGUuY29tAAAAAAlQbGF5ZXIgMgAAAAAUcGxheWVyMkBleGFtcGxlLmNvbQA=\nAccept-Language: en-us\n```\n\nThe interesting portion here is the cookie `HasbroCookieVR1`, containing a Base64-encoded binary structure with information about the to/from email addresses, game snapshot, and other information.  This is similar to a POST request with the same information in the body.\n\nThe server response is parsed for certain HTML tags - mainly, a `\u003cPRE\u003e` block with a Base64-encoded server binary response.  A sample response accepted by the client looks like this:\n\n```\nHTTP/1.0 200 OK\nDate: Sun, 26 Sep 2021 05:49:53 +0000\nContent-Length: 1658\n\n\u003cHTML\u003e\u003cTITLE\u003etitle\u003c/TITLE\u003e\u003cBODY\u003e\u003cPRE\u003e\nAAAAAAAAAAAAAAADAO7/DAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHRlbXB4ZW0AAAAEKVY+\nF/+pwRlLIcHzpVtxLsSTlkR+EtLw0usmTXBgNw7lQmyTv+cmt2rb1Y1qTiHk2PPNJVkHzKiLfjZc\n1tqQcFcT4NDwZF80gsfV/SBJeKvCjV5FbpPA6xY7Zp223QIxWI+sR/8nUnuiyfYdRGuYw+4TOmCO\nteUJJFqEp9f/Kh0E4cz1G0dynMLpGD1kibjjBjPOhK7VAylQeKTP8x9KdJrF6BU8Y5C34wsyXIal\n3QEoDwPnzvcmSXCdxO8fP2qbuuEANcyGsNsBK1Z+ps3+IUh1nMPtF0JqkrXhDTBeiLvZAy6BAOXQ\n+SVLdprG7QhBaJ+85wI38oiy2QAtVHuo0/wjTnOewfIZQGmUs+UPPmCKud4FLMf+69L7Ik10mcjz\nEUNumb7lHDnwirTfBy9agKrR+SVMcqDP8RtGbpax6hE8Yoy/2gcyQf3p1P0gT3qnyvERRWyWwOse\nO/aMtt0MMViHrNf9J1J6os33HURsmM/uEypkjrXiCTBYhK/S/ypUeqHK9RxGcJOSh3VEA/2Y0wok\nLOnPrmVbYDvBtZdyOB3/7Y96U2fguOIJMl2AqdgDiiw+pc7zIEt2m8bvFj1lkbjnDKdfh7LbAilW\nfaTL+CNOc5rA7hVFaZy95B89X4pFWkEsVXin0v8iSXWdxOYYQ26TLuQONWOJsNgEL1d/qtD6JUp1\nnMHwF0VrhrXmDRDhyLPcAy5VhqnQ+iRPcJ/K9RrRbZW85hA7Y4u22AYtXYGs1/wnSneuwfIJTW2U\n02hTOmOLtdwAMFuBq9b+Jk18oVjyHEdql8LtEjlijbTZCDdYg67X/ilZebDM9B+iENrB6hc8Z4q3\n4goyWYKt1Psow3ujzvceRXKZwO0UP2CPvuIKMV+FoNwAO1h7pn12XUhxnMPuEz5llbngCjRfgq9K\nACpReKXM8yBLcZvG7hY5a5G44Aw7VIee2AIhNhHJrJNSZBHxte4SJg+QqlrfpvkhHRXM45oYwbmR\nnZjmO29DI46lXNqDDSXP9w4L4D5gsGQenEUS2SAVRdAfeKyO1TxYbY+gY9Z58SkFfuiI4c4yZVyq\nPv0wFEqolM8mDY1XtgwZOFeovPfu8Jg4lt7gDDJ1nKDuRjhEiqvjr4WCZr3ULozkSZvexSxrQrmQ\nzyYddKOK8SgBeFOK/dQPZqgVUg6M1dk881C9hNMmm13iy7CZ52u1lQM60nfZ86SNclupQ3fWxfyT\nvwfQZk80HWv0OSmHvlUMRUpYAfbf0Tn7akpgFziDWXCpwvvvhr2vCyLZD8E9Fk+gmZFIfxbN5JhM\nD2NUjebfzsXsBUBrk7vmCjBbd7HaAizAcKfS/CJLhZvG7+pJa2C15Po3YI1K2wQor3ysKfkmtXeY\nMvIetG6eTOAFymmBQNUO2lfJIieZLQUT86SeNmMb+syLdBhieQAAAAA=\n\u003c/PRE\u003e\u003c/BODY\u003e\u003c/HTML\u003e\n```\n\nThe client parses this and looks for certain flags indicating a successful response, then informs the user that submission was successful.  Most of the data in the response structure is not known, but some flags allow sending a custom error message, indicating error status, etc.\n\nThe server's task is to pass the turn snapshot (`.xem`) to the next player.  The original role of the Hasbro servers was to wrap this in an email message.  It is up to the dev to determine what to do with it in this case.  I have connected the output to a Discord webhook, which notifies the players and attaches the `.xem` for the opponent to pick up and play.\n\nFor details of the binary structure itself, please see the comments in the source code.\n\n## Usage\nThe handoff server is written as a `.php` file which parses the cookie and constructs the response.  Setting this up requires a PHP-enabled web server, listening on the desired port and sending requests to the script.  Path parameters should be parsed into a single query parameter `timestamp` of form `seconds.milliseconds`.\n\nFor example, this `httpd.conf` VirtualHost directive for Apache listens to incoming requests on port 8080, and forwards them to the script residing in `/usr/local/www/pbemproxy/index.php`.  Adjust especially the FilesMatch portion if you use `mod_php` instead of an FPM service, etc:\n\n```\n\u003cVirtualHost *:8080\u003e\n  ServerName 128.11.41.76\n  ServerAlias 128.11.41.77\n\n  DocumentRoot \"/usr/local/www/pbemproxy\"\n  \u003cDirectory \"/usr/local/www/pbemproxy\"\u003e\n    DirectoryIndex index.php\n\n    # Controls who can get stuff from this server.\n    Require all granted\n\n    # Set up the PHP handler\n    ProxyErrorOverride on\n    \u003cFilesMatch \\.php$\u003e\n      SetHandler \"proxy:unix:/tmp/php-fpm.sock|fcgi://localhost\"\n    \u003c/FilesMatch\u003e\n\n    RewriteEngine On\n    RewriteRule \"^(\\d+)/(\\d+)\\.htm$\" \"/index.php?timestamp=$1.$2\" [L]\n\n  \u003c/Directory\u003e\n\u003c/VirtualHost\u003e\n```\n\nAlternately, if you just want to *play* the game without any of this, there is a Discord server available with the correct setup.\n\nClick here to join: https://discord.com/invite/xB4XsTeFta\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgreg-kennedy%2Fhasbropbemproxy","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgreg-kennedy%2Fhasbropbemproxy","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgreg-kennedy%2Fhasbropbemproxy/lists"}