Jump to content


  • Content count

  • Joined

  • Last visited

  • Days Won


Everything posted by Ben

  1. Hello Person, Thanks for joining Solero. In response to your question, there is a column in the database called "Moderator", you can set this to 1 for your player in the database using PHPMyAdmin in order to mod yourself in the game. I would like to suggest you join your Discord server, however, since the tutorial you followed is now outdated. On our Discord server you can get help setting up Houdini, we have detailed a text tutorial for Ubuntu and we're working on more.
  2. Hello everyone, Many Club Penguin Private Servers make use of only one world server, this is generally a good thing as it keeps all of your players together and helps encourage social interaction between players in the game. Club Penguin has always given the players the option to choose which world server they want to join, but if there is only one world server, what's the point in providing users the option? I wrote some code which will give you the ability to remove the world selection screen from the game entirely, this not only makes login faster thanks to not having to ask the user for input, but also because we no longer need a login server at all, we just authenticate with the world server and call it a day. Here is the actionscript code for the dependency shockwave flash file: import com.clubpenguin.util.*; import com.clubpenguin.crypto.*; var SHELL = _global.getCurrentShell(); var AIRTOWER = _global.getCurrentAirtower(); AIRTOWER.connectToLogin = function(in_username, in_pass, login_response) { if (!AIRTOWER.is_logged_in) { AIRTOWER.on_login_response = login_response; AIRTOWER.username = in_username; AIRTOWER.password = in_pass; AIRTOWER.server.onConnection = Delegate.create(AIRTOWER, AIRTOWER.handleLoginConnection); AIRTOWER.server.onExtensionResponse = Delegate.create(AIRTOWER, AIRTOWER.onAirtowerResponse); AIRTOWER.server.debug = true; AIRTOWER.addListener(AIRTOWER.HANDLE_LOGIN, AIRTOWER.handleOnLogin); var _local1 = SHELL.getWorldCrumbs(); var _local2; var _local3; for (_local2 in _local1) { _local3 = _local1[_local2]; break; } SHELL.world_id_holder = _local3.id; AIRTOWER.server.connect(_local3.ip, _local3.port); } else { AIRTOWER.shell.$e("connectToLogin() -> Your already logged in! Cant login again"); } } AIRTOWER.handleLoginConnection = function(success) { if(success) { AIRTOWER.login(); } else { AIRTOWER.on_login_response(false); } } AIRTOWER.login = function() { AIRTOWER.server.login("w1", AIRTOWER.username, AIRTOWER.getLoginHash()); } AIRTOWER.handleOnLogin = function(obj) { AIRTOWER.removeListener(AIRTOWER.HANDLE_LOGIN, AIRTOWER.handleOnLogin); AIRTOWER.shell.setMyPlayerId(obj[1]); AIRTOWER.playerId = obj[1]; AIRTOWER.login_key = obj[2]; AIRTOWER.on_login_response(true); AIRTOWER.is_logged_in = true; SHELL.gotoState(SHELL.PLAY_STATE); } SHELL.connectToWorld = function() { var _local1 = SHELL.getWorldById(SHELL.world_id_holder); SHELL.showLoading((SHELL.getLocalizedString("Joining") + " ") + _local1.name); AIRTOWER.joinWorld(); } AIRTOWER.handleJoinWorld = function(obj) { AIRTOWER.removeListener(AIRTOWER.JOIN_WORLD, AIRTOWER.handleJoinWorld); var _local6 = Boolean(Number(obj[1])); var _local3 = Boolean(Number(obj[2])); var _local5 = Boolean(Number(obj[3])); var _local4 = Boolean(Number(obj[4])); AIRTOWER.on_world_response(true, _local6, _local3, _local5, _local4); AIRTOWER.on_world_response = undefined; } AIRTOWER.joinWorld = function() { AIRTOWER.server.onConnectionLost = Delegate.create(AIRTOWER, AIRTOWER.handleLostConnection); var _local2 = new Array(); _local2.push(AIRTOWER.playerId); _local2.push(AIRTOWER.login_key); _local2.push(AIRTOWER.shell.getLanguageAbbriviation()); if (AIRTOWER.isRedemption) { AIRTOWER.addListener(AIRTOWER.REDEMPTION_JOIN_WORLD, handleJoinRedemption, AIRTOWER); AIRTOWER.send(AIRTOWER.REDEMPTION, AIRTOWER.REDEMPTION_JOIN_WORLD, _local2, "str", -1); return(undefined); } AIRTOWER.on_world_response = SHELL.connectToWorldResponse; AIRTOWER.addListener(AIRTOWER.JOIN_WORLD, AIRTOWER.handleJoinWorld); AIRTOWER.send(AIRTOWER.PLAY_EXT, (AIRTOWER.NAVIGATION + "#") + AIRTOWER.JOIN_WORLD, _local2, "str", -1); } AIRTOWER.getLoginHash = function() { return SHA256.hash(AIRTOWER.password); } Now, since the way that the client authenticates is slightly different, your server will need to be modified to support it. In this case, I actually made mine use SHA256 hashing (thanks @Kevin) instead of MD5. There is also now no real need for a random key. Note you do not need to use SHA256 with this, it was just what I decided I wanted to use, if you want to go back to MD5, or use another authentication method entirely, you can do so by overriding 'AIRTOWER.getLoginHash'. With this code the client connects directly to the first localized world server in the world crumbs, performs the handshake, hashes the password and authenticates, then proceeds to get the players information. This is how the world server auth works: recv: <msg t='sys'><body action='verChk' r='0'><ver v='153' /></body></msg> send: <msg t='sys'><body action='apiOK' r='0'></body></msg> recv: <msg t='sys'><body action='login' r='0'><login z='w1'><nick><![CDATA[Ben_]]></nick><pword><![CDATA[SHA256]]></pword></login></body></msg> A couple of actionscript classes are required for this code to export, everything is zipped below, you'll also find a pre-exported version in there if you are happy to use mine. The SWF file goes in /play/v2/client/ of your media server, please add it to dependencies.json too: { boot: [ { id: 'airtower', title: 'Communication' }, { id: 'sentry', title: 'Communication' } ], login: [ { id: 'cookies', title: 'Login Screen' }, { id: 'login', title: 'Login Screen' } ], join: [ { id: 'engine', title: 'Engine' }, { id: 'interface', title: 'Interface' }, { id: 'gridview', title: 'Gridview' }, { id: 'mail', title: 'Mail' }, { id: 'book', title: 'Mail' }, { id: 'stampbook', title: 'StampBook' } ], create: [ { id: 'create', title: 'Create Penguin' } ], merch: [ { id: 'app', folder: 'merch/', title: 'Communication' } ] } End result: Please suggest improvements, specifically ways to improve the security, I'm sure this is pretty half-assed. Please ask if you're having troubles getting the server sided stuff to work. Works on only legacy private servers, not the new client, but could be easily ported. I'll do it if I ever find the time. cookies.zip
  3. Welcome to Solero! Please feel free to join our discord community. If you haven't already.
  4. Hi Andrey, welcome to Solero. If you want to write your own game server for a CPPS, then it is worth reading up about what a socket server actually is, you clearly already have some idea about what the task is that you are undertaking! A CPPS game server is basically a socket server that responds to two different types of packets, XML (or login) packets, and XT (or game/world) packets. There are a few other things which are really essential if you wish to write a game server for a CPPS: Full understanding of the Club Penguin Protocol. You can learn this by either reading the action script code hidden inside the Club Penguin client files (this involves downloading a media server and opening files up in JPEX decompiler), or, by looking at other, already built source codes and seeing how they work (this is how most people learn). In-depth knowledge of how to write code in a programming language of your choice. Any programming language will probably do just fine, I recommend a higher-level interpreted language (and perhaps one that supports parallel programming?) since it sounds like you might be a beginner. Don't choose a language because someone told you it's faster, choose one you're good at, and stick with it. Knowledge of some kind of database software, since your game server is going to have to store data about users somewhere. You do not have to use MySQL, there are actually tons of other great database servers out there, however MySQL is a popular choice thanks to its good support for small sized databases and documentation scattered around the web, not to mention the numerous libraries & ORMs compatible with MySQL & SQL in general. So to answer your questions tl;dr mode Yes, learning about socket servers, specifically TCP, is essential. With some languages & their libraries these days you can write a TCP socket server in 10 seconds flat, however you'll never write a whole CPPS game server in under an hour!? You don't have to use git, although it's a handy tool for keeping track of your work, it's not a necessity, but extremely helpful. If you don't know how to use git, I would recommend you focus on implementing the base of your server first, rather than faffing around trying to learn git, which can be a fairly large topic in itself. Yes, as I stated above, reading sources already made is a very good idea. I would recommend reading through sources like Kitsune or Houdini to get yourself started. Hope I helped a little, good luck & have fun!
  5. Official thread for Icer.ink - Club Penguin Media Archive Hello everyone, I have recently taken it upon myself to produce a clone of Club Penguin's client media. I built this by parsing JSON and XML configuration files, but also by making use of other techniques such as basic web scraping and by auditing a lot of the action script code inside the client files. The end result is around 4GB of game media (uncompressed). The root directories are named after their respective web domain. Browse the directories Download media (4.4GB)
  6. Added. Also added some missing postcard icons. tf? Added these: https://icer.ink/media1.friends.go.com/css/themes/CP/D_F_btnClose.png https://icer.ink/media1.friends.go.com/css/themes/CP/D_F_btnCloseHover.png Added media for "Welcome to Club Penguin" experience for new players!
  7. Quick notice for private server owners. Please DO NOT proxy your media servers through to Icerink like some of you are doing. It is putting heavier load on my box, not to mention you're putting yourself at risk, since if my server is vulnerable, so is yours. Please download Icerink completely and mirror it on your web-server, your performance will improve that way too. Thanks!
  8. Cool. I've added them to the archive! Thanks for your help, providing that list of paper IDs really saved me time. Credit @DJ_MuTeD 's FreePenguin for the _back.swf files. Also re compressed the whole archive and updated download.zip. Not accidental, sure this directory existed, and is referenced to in some of the game configs, however it was empty when I checked it. The puffle files which were there had been moved elsewhere. Rotom-Wash has been added to contributors.
  9. I looked for these when I initially created the archives, however I couldn't find them on Club Penguin's media server (media1 or media2), can anyone actually confirm these WERE on Club Penguin's media when it closed? I know they must have been at some point, since FreePenguin has them up, but those could be outdated.
  10. Hey everyone, It is clear to me, and many of you, that things are a little.... quiet? I'm not necessarily talking about Solero, but our community in general, especially on the development side of things. 2017 was a big year for us to some degree, the closure of the Club Penguin game meant we saw a short uproar in activity and productivity, for some time people were showing a lot of interest in private servers again, and many ex-cp players were looking to make their own servers, I know this because shortly after Club Penguin closed, I was approached by around 50 individuals asking for help, which of course I offered! It was a breath of fresh air to me, going back to how things were just a few short years ago. It has now been two years since the closure of Rile5.com, which I still miss, honestly, the nostalgia I'd get from visiting that site again would truly be insane. I am proud to have been involved in all this, however, it is a very big part of my life, a part I can't imagine I'll ever forget. My love for computer programming and hardware was born from the people in the CPPS community, I can't help but think how different things would have worked out for me had I not registered on the beloved R5 :) Anyway things are slowing down again. What does the future hold for Solero? Solero is STAYING, this box isn't used solely for Solero, so it will stay for as long as my need for this server stays. The icerink archive stays until it gets taken down by ledisney. I will always be around, but I'm no longer actively writing code, helping people out or working for clubpenguin-related projects, mainly because there's no demand for help but also because I've grown out of this. Solero will also get maintained in my free time, so I don't get hacked. If you make a topic here I'll probably read it. What does the future hold for the community? The official death of flash has really marked the end of the road, with HUGE clients such as Chrome, Firefox and Edge thinking of throwing in the towel, things really don't look promising, the chances of flash becoming FOSS are slim, IMO. I don't think private servers will still be around for the 2020 exit of Adobe Flash, however, Club Penguin simply isn't an impressive game by today's standards, kids can get so much more out of other platforms. If you have been a part of this community, thank you for helping make my childhood slightly more interesting . Good luck to you all, I wish you the best.
  11. Hey everyone. Apps built on web tech have been growing in popularity hugely recently thanks to their portability, share your favorite Electron program! Mine is Visual Studio Code. I also like Slack, KeeWeb, Github Desktop & Whale.
  12. Thanks guys! I've added these files and updated download.zip. Nope
  13. What are the file names of everything inside this directory?
  14. Hey everyone, I frequently see people struggling with disableing the domain locking, logging services, and client checks embedded into Club Penguin client files to prevent the files being used outside the http://clubpenguin.com domain. I have written a tool in Python to help aid the process of disabling these functions, whilst maintaining the crossdomain policies within the files which actually act as a security feature. import zlib import logging import argparse from os.path import isfile, isdir, splitext, join, exists, dirname from os import walk, makedirs from glob import glob if __name__ == "__main__": logger = logging.getLogger(__name__) logging.basicConfig(level=logging.INFO) parser = argparse.ArgumentParser(description="Club Penguin client tool") parser.add_argument("path", type=str, nargs="*", help="Path(s) to files or directories") parser.add_argument("-d", "--domain", type=str, help="The domain to use (ex. clubpenguin.com)") parser.add_argument("-r", "--recursive", action='store_true', help="Enables recursive mode") parser.add_argument("-o", "--output", type=str, help="Output directory") parser.add_argument("-D", "--dump", action='store_true', help="Dump decompressed FWS data") arguments = parser.parse_args() logger.info("This program can overwrite files on the disk, make sure to make backups before" + " running this script or make sure the output flag is enabled!") for path in arguments.path: if isfile(path): logger.info("Found \"%s\"", path) paths = [path] elif isdir(path): if not arguments.recursive: logger.warning("\"%s\" is a directory but recursion is disabled! skipping...", path) continue else: paths = [y for x in walk(path) for y in glob(join(x[0], '*.swf'))] for file in paths: logger.info("Found \"%s\"", file) filename, file_extension = splitext(file) if file_extension != ".swf": logger.warning("\"%s\" is not an SWF file! skipping...", path) continue logger.info("Opening \"%s\"", file) raw = open(file, "rb") signature = raw.read(3) logger.info("Reading file signature for \"%s\"", file) if signature != b"CWS": logger.warning("File has invalid signature, file sig should be 0x43 0x57 0x43(\"CWS\")") continue header = raw.read(5) data = raw.read() logger.info("Read %d bytes from \"%s\"", data.__sizeof__(), file) logger.info("Decompressing") decompressed_data = zlib.decompress(data) original_data = decompressed_data if b'\x00clubpenguin\x00boot\x00BootLoader' in decompressed_data: logger.info("Found a BootLoader, cracking client checks...") s = b'\x00logEvents\x00boot\x00BootL0ader' decompressed_data = decompressed_data.replace(b'\x00logEvents\x00boot\x00BootLoader', s) s = b'clubpenguin.c0m' decompressed_data = decompressed_data.replace(b'clubpenguin.com', s) if b'clubpenguin.com' in decompressed_data: logger.info("Found clubpenguin.com") s = bytes(arguments.domain.encode()) decompressed_data = decompressed_data.replace(b'clubpenguin.com', s) if b'disney.com' in decompressed_data: logger.info("Found disney.com") s = bytes(arguments.domain.encode()) decompressed_data = decompressed_data.replace(b'disney.com', s) if decompressed_data == original_data: logger.warning("No changes were made to the data!") continue logger.info("Re-compressing data and appending file signature and header") compressed = signature + header + zlib.compress(decompressed_data) if arguments.output: file = join(arguments.output, file) if not exists(dirname(file)): makedirs(dirname(file), exist_ok=True) if arguments.dump: dump = open(file + ".fws", "w") dump.write(str(decompressed_data)) dump.close() logger.info("Copied dump to \"%s\"", file + ".fws") logger.info("Writing data to \"%s\"", file) output = open(file, "wb") output.write(compressed) output.close() raw.close() logger.info("Finished. Goodbye!") If you know Python a little then you will probably be able to understand how the script works rather quickly, as it is rather simple. It decompresses the SWF files to expose some of the actionscript constants within the file (no, this script does not make use of SWF disassemblers like RABCasm which makes my script very lightweight and very fast) The script has a few flags, some of which are just useful, and some of which you'll probably want to use every single time you run it. $ py iceburg.py -h usage: iceburg.py [-h] [-d DOMAIN] [-r] [-o OUTPUT] [-D] [path [path ...]] Club Penguin client tool positional arguments: path Path(s) to files or directories optional arguments: -h, --help show this help message and exit -d DOMAIN, --domain DOMAIN The domain to use (ex. clubpenguin.com) -r, --recursive Enables recursive mode -o OUTPUT, --output OUTPUT Output directory -D, --dump Dump decompressed FWS data Domain (required) tells the script which internet domain to replace security locks and logging services with. Recursive mode will make the script search through every directory below the path you specify for SWF files to check. Output changes the output directory, assuming the output directory is empty no files will be overwritten. Dump will make extra files containing the decompressed version of the data, useful for debugging purposes (for example if the script is making changes which break the SWF). Example usage on real Club Penguin media! /play/v2/client /play/v2/games/ Script download attached :~) Prerequisites Python 3 :) client-tool.zip
  15. You're welcome! Yes, it will stay up for as long as I have spare change at the end of the month to pay for our box. There is actually a plethora of files which were used for the various different versions of mobile apps created by Club Penguin, and I voted against putting them on Icerink due to time constraints and lack of real need for them as it is very unlikely anyone is ever going to bother reverse engineering the mobiles apps (they sucked anyway). I can see how the paper image directories may be useful to people and I'll look into uploading them. I also downloaded lots of files off of the media8 subdomain before I decided to give up, maybe I'll put those up soon too.
  16. Very curious, I thought I was quite careful when downloading minigame assets, I checked every SWF file individually for dependencies. I even remember downloading these ones, guess I forgot? I noticed a few extra missing ones from your zip file still on Club Penguin's media server, so I grabbed those too! Thanks for flagging this up, added you to contributors. updated - https://icer.ink/media1.clubpenguin.com/play/v2/games/jetpack/
  17. It seems this library actually lets you carry out other work whilst a request is in progress, perhaps a solution? https://github.com/stil/curl-easy You could even make use of Kitsune's event timing system to get the response from Discord.
  18. You have to make a value inside game_strings.json called w.app.februrary2017.town.jacket and assign the value to whatever you wish to make the text say I think. You may need to copy your modified game_strings into game_configs.bin using WinRAR or 7-Zip.
  19. play, media1, media2 (which just points to media1), media8 and directory are the essential ones. I know directory isn't on icer.ink, but you should make it.
  20. First you're going to need to download some Club Penguin media. You can get it all from http://icer.ink. Your VPS is going to need to have a webserver (I reccomend you use nginx), PHP and a MySQL database installed. Upload the media to your webserver webroot and extract it, then configure subdomains (respective to the ones from icerink) on your own domain and your webserver to point those domains to the respective webroot folder in the media you downloaded from icer.ink. Next you'll need to crack the Club Penguin client to disable domain locking, this essentially just involves replacing actionscript constants within files inside the /play/v2/client/ & /play/v2/games folders inside the game media directories. You can do this manually using JPEX free flash decompiler or you can use a tool I wrote in Python specifically for this process. You'll also need to modify global_crumbs.swf to point the game client to the correct address and ports that Kitsune will run on. Edit the files inside your play subdomain webroot to work on your domain (instead of clubpenguin.com), or just create a new HTML webpage which embeds club_penguin.swf. Now go and clone Kitsune out of its official repository, and configure it for your server. Execute Kitsune.sql on your database. Create a user account in your Kitsune database, run Kitsune on your server, and login via the play page. Very brief, and I purposely missed out huge amounts of detail but you can always ask for more specific help.
  21. Unfortunately, because curl_exec is a blocking call, your server will actually hang whenever a post is made to the Discord webhook API. I did this a few weeks ago, and even with two users online, the effect on performance was noticeable, and this could very easily be abused by creating bots which login to the server repeatedly. PHP is able to execute multiple curl requests at once, but there isn't a way (as far as I know), to carry on with your socket server loop before the requests are complete, not without using an extension which brings real multithreading to PHP, like pthreads. A nice idea, and it works, to a degree, don't use this if your server has many players. :)
  22. Hiding your VPS' IP address is just security through obscurity and it's reccomended you always steer clear of these approaches, even though quite often they might be worth implementing anyway. Ultimately your CPPS has a game client, which must connect to a game server, you can't hide the address. What you can do is make use of a reverse proxy to try and filter attacks, there are services online (which you pay for), which offer "DDoS protected" reverse proxies, as you would be pointing your game client to the proxy address, you would, in essence, be "hiding" your real game server IP. There are also virtual server hosting providers such as OVH who provide DDoS protection as part of all of their plans (paid for by distributing the cost across all of their customers). Beware though, lots of hosting providers claim to be able to protect you from attacks, but can't, make sure to read up on reviews before getting ripped off. You should read up on how to secure linux servers from different types of attack, before trying to setup any services which you run publicly, it only takes one google search to find out how to do things the correct way, and of course you're always welcome to make support topics here if you're stuck with anything.
  23. Hey, welcome to Solero!
  24. Not sure if this is the default one.