Merge branch 'dev' into nuxt-refactor

This commit is contained in:
mrjvs
2026-08-09 21:09:14 +02:00
71 changed files with 5024 additions and 572 deletions

171
content/blog/12-25-25.md Normal file
View File

@@ -0,0 +1,171 @@
---
title: "Christmas Progress Update"
author: "Jon"
author_image: "https://www.github.com/jonbarrow.png"
date: "December 25, 2025"
caption: "Internal changes, Juxtaposition, 3rd party servers and more"
cover_image: "/assets/images/blogposts/december-25-2025/banner.png"
---
These last few months saw a large focus on internal changes to our systems, internal gRPC services, and improvements to Juxtaposition, amongst others!
# Animal Crossing: New Leaf
As I’m sure you all remember, on July 24th of this year, we made the unfortunate announcement that we were taking our Animal Crossing: New Leaf servers offline, indefinitely. This was in direct response to reports of an RCE exploit being actively used in the game.
To reiterate, this is an exploit *within the game itself*. It was not caused by our servers, and in fact can be exploited when not online at all via local wireless play. Even still, we felt it best to take the servers down to limit the impact while we investigated.
After several months of testing, research, and talking with famous Animal Crossing content creator [Hunter R.](https://www.youtube.com/@Hunter-R.), a working patch for the exploit was made. Animal Crossing: New Leaf is back online for ALL users as of December 8th! We would like to thank everyone for their patience, and thank all of our testers for helping with the process.
For a deeper explanation of what the exploit is, how it worked, and how we are patching it, see [Hunter R.’s breakdown video on YouTube](https://youtu.be/pV0xnIsgGXE).
# Technical Updates
## Account Server
When logging into your account, the server issues 2 tokens:
1. A short lived access token
2. A long lived refresh token
The access token is used by the console/games to identify your account with the account server, for reasons such as querying for user data, requesting additional tokens, etc. These tokens are short lived, forcing a client to reauthenticate after they expire. In order to skip the normal login flow, the client may send the refresh token to the server to "refresh" the login session, getting back a new set of access/refresh tokens.
One of the biggest long-standing bugs with our account server is that it issued "useless" refresh tokens, which were unable to actually refresh the session. This was because refresh tokens were expiring at the same time as the access tokens! Refresh tokens now properly expire and are actually usable.
At the same time, we also changed how service tokens are handled. A "service token" is a token issued by the account server for an "independent service". An "independent service" is essentially any server a game needs to operate which is not a game server written using the NEX library. These are most commonly used by 3rd parties to implement their own servers (RPG Maker FES, Colors! 3D, etc.) or to add supplementary servers that assist the main NEX game server (Super Mario Maker's bookmark site, Pokemon legality checking, etc.). These service tokens are requested using the accounts access token and provide developers a way to ensure a user passed the normal authentication checks to obtain the token, as well as a read-only way to interact with user data.
Initially, we treated service token expiration the same way we treated all token expiration. The token has an associated "expiration time" and, when used on the account server, it would validate that time, rejecting any tokens that had expired. However, this was later found to be inconsistent with how we observed some services operating. [Dani](https://github.com/DaniElectra) noticed some time ago that there are references to [local expiration on the 3DS](https://github.com/PretendoNetwork/juxtaposition/pull/114#issuecomment-2863503035). We also noticed that the request to WaraWara Plaza data seems to always use the same token, no matter how much time has passed. These 2 things, when combined, seem to indicate that service tokens, officially, either did not ever expire, or the expiration was ignored when the independent service validated the token with the account server, presumably allowing each independent service to decide how long a token should be "alive" for.
In light of these observations, we have now also changed our service token handling to be more accurate to the behaviour we observed. Rather than tracking an "expire time", service tokens now track an "issued time", allowing each independent service to pick the length of time a token should be valid for. This marks the first step in our larger plans for a total overhaul of how tokens/account data is processed.
## Account Deletion
Until recently, the only ways to delete your account were using a console or by requesting a deletion via our support forums. We have now updated our account server's internal gRPC service to allow for account deletion requests. This uses the same mechanism under the hood as used by the on-console “Delete Account” button, but now allows us to trigger an account deletion from anywhere we choose. This has allowed us to add a “Delete Account” button to both the website, for you to delete your own accounts without needing a console, and to our admin panel, for moderators to take immediate action in extreme cases.
Additionally, deleting your account will also automatically delete personal data from supported services, such as the forums and Juxtaposition.
***NOTE: DELETING YOUR ACCOUNT WILL NOT FREE YOUR USERNAME FOR REUSE. USERNAMES CAN NEVER BE USED AGAIN ONCE ASSIGNED TO AN ACCOUNT***
## BOSS (SpotPass)
BOSS is a system Nintendo provided to allow titles to request/store data (called objects) using background tasks. This is most commonly used for the SpotPass feature, but is also used to deliver data like system notifications, Splatoon rotations, etc. Over the past few months, we have been working on improving our BOSS server both in terms of developer usability and its general operations. The BOSS server received several upgrades to both how we store and process SpotPass files, our internal gRPC service for managing files, as well as improving our data storage and transport systems. All of these combined should provide a much better SpotPass experience for both users and our team, allowing us to more easily ship data like in-game content, console notifications, etc.
## gRPC
As mentioned in [Account Server](#account-server), we have begun making some updates to our internal [gRPC](https://grpc.io/) services. We use gRPC for [interprocess communication (IPC)](https://en.wikipedia.org/wiki/Inter-process_communication) as a way to communicate and request/send data between services as it is fast, lightweight, strongly typed, and allows services to be easily defined via [protocol buffers](https://protobuf.dev/). [Quarky](https://github.com/ashquarky) recently added the ability to [request device information](https://github.com/PretendoNetwork/grpc/pull/3) for devices linked to a user's account, and we have also begun adding a way to [exchange service tokens for account data](https://github.com/PretendoNetwork/grpc/pull/6). Additionally, we have also begun exploring a brand new [NEX gRPC service](https://github.com/PretendoNetwork/grpc/pull/5). This service would live inside game servers and allow us to interact with them more efficiently, for features such as:
- Moderation. Having a link to the game servers will allow us to kick existing clients from games in instances like account/device bans
- Live notifications
- Pulling server statistics like player counts, multiplayer match data, information about UGC, etc.
## Misc
These are some smaller changes compared to the ones above, but still deserve mentioning
- [Will](https://github.com/binaryoverload) upgraded our [BOSS server to Express 5](https://github.com/PretendoNetwork/BOSS/pull/22). While not a huge change by itself, Express 5 brings in many [new features and improvements](https://expressjs.com/en/guide/migrating-5.html) that we can take advantage of
- [Dani](https://github.com/DaniElectra) has updated our documentation wiki both with [the latest upstream changes](https://github.com/PretendoNetwork/nintendo-wiki/pull/43), as well as [new additions to some older NEX protocols](https://github.com/PretendoNetwork/nintendo-wiki/pull/44)
- The account server received some minor bug fixes. Those being a bug with the 6 digit email codes which would incorrectly block registration if a code was in use by another account already, as well as a bug where 3DS devices would not be properly linked to an account when using the NNAS service, and some updates to token validation
- Various research into many games (including those not on the Wii U/3DS) continues to drive our understanding of these games forward, and continues to be documented on our wiki. We now have documentation for [several previously undocumented protocols](https://github.com/PretendoNetwork/nintendo-wiki/pull/52)
- [JVS](https://github.com/mrjvs) made a new [SMTP relay server](https://github.com/PretendoNetwork/smtp-relay) that has been introduced for use on the forums. Our forums are powered by [Discourse](https://discourse.org/), which requires that *all* accounts have a unique email address. NNIDs, and subsequently PNIDs, do NOT require unique email addresses. As a workaround for this, every forum account is assigned a fake email address using each account's unique PID value. This lets us link PNIDs to the forum, but breaks email support. This new SMTP relay runs alongside the forum and maps the fake email address back to the account's real email address, allowing for email notifications to finally work on user accounts
- Splatoon rotations are now fully automated. Previously, we were working with [OatmealDome](https://github.com/OatmealDome), who used his [Rotationator](https://github.com/OatmealDome/Rotationator) tool to generate our Splatoon rotations every few weeks, which we would then manually upload. Utilizing the new updates to the BOSS server, we were able to [fork OatmealDome’s tool](https://github.com/PretendoNetwork/Rotationator) and completely automate the process
# Juxtaposition
Juxtaposition has received a large focus over the past few months. Many hands touched these changes, thank you to [Jemma](https://github.com/CaramelKat), [Quarky](https://github.com/ashquarky), [jvs](https://github.com/mrjvs), and everyone else on the team, as well as all of our outside contributors! There are too many individual changes to list here, so only the biggest changes/PRs will be listed. To get a full breakdown of all the changes, please see the official [Juxtaposition GitHub repository](https://github.com/PretendoNetwork/juxtaposition/) and the [`#github` channel on Discord](https://discord.com/channels/408718485913468928/473698995286573066)
Ingest and processing of images has been overhauled, making more compressed and thumbnail versions of uploaded paintings and screenshots. On pages with lots of images, this makes Juxtaposition load dramatically faster and reduces memory load on 3DS systems especially.
![A Juxtapositon post. "my first house!". An image of a Minecraft house is attached.](/assets/images/blogposts/december-25-2025/image8.png)
*Screenshots like these used to be quite a problem for 3DS users. The full-size version of this image, as uploaded by the Wii U, is 88KiB. The new thumbnail version shown on 3DS is 12KiB - an 80% improvement!*
These changes also include aspect ratio tracking for uploaded images, in case.. future changes involve uploading screenshots of other aspect ratios, for some reason. :) Tracking aspect ratio also helps improve content shift on load.
![An animation showing a Juxtaposition post loading in, with the images appearing gradually.](/assets/images/blogposts/december-25-2025/image4.gif)
*The layout used to move around a lot while the images loaded. Now, everything maintains its proper size during loading. (Load times increased for clarity)*
Banners for 3DS communities can now have a small background area behind the community info. We’ll be steadily updating communities to take advantage of this design.
![An image of Inklings in battle. Below a purple border and on a gold background, the stats for the Juxtaposition community are listed.](/assets/images/blogposts/december-25-2025/image3.png)
*Splatoon is one of the communities featuring the new design.*
On 3DS, Juxtaposition now calls for manual garbage collection after each page load. This helps clean up unused memory and free it up for the new parts of the page. On the Old 3DS, this appears to have nearly completely eliminated the “blue screen” out of memory issues.
![A screenshot of the Homebrew Community on Juxt 3DS, revealing a solid blue background to the right.](/assets/images/blogposts/december-25-2025/image5.png)
*The blue background is always there, you just can’t see it. We hope.*
On 3DS, Juxtaposition’s design assets have been optimised and re-encoded - things like the background pattern, coloured headers, and tab background. Combined with JavaScript delivery improvements, page sizes (excluding images) have dropped by 60%.
![A grid of various icons.](/assets/images/blogposts/december-25-2025/image2.png)
*Juxtaposition on the 3DS uses this spritesheet for the bulk of its design assets to reduce load times. This way, the console only has to load one large image and show different portions of it. Compression makes this more efficient than loading a dozen smaller images.*
Some quick-fire updates:
- The [logic for creating a new post has been updated](https://github.com/PretendoNetwork/juxtaposition/pull/129) to fix several bugs and "smelly" code
- A new [audit log has been implemented](https://github.com/PretendoNetwork/juxtaposition/pull/136) to track actions performed by moderators
- A new [JSX-based rendering system](https://github.com/PretendoNetwork/juxtaposition/pull/132) is being worked on
![A Juxtaposition DM thread on Wii U. Luca messages Jon about a Splatoon battle. Jon does not respond.](/assets/images/blogposts/december-25-2025/image1.png)
*Message threads are one of the pages on the new JSX renderer.*
- Updates to [the new token format](https://github.com/PretendoNetwork/juxtaposition/pull/131) are being worked implemented
- Several parts of our build system have been improved and the UI portions of the applications are slowing being ported to TypeScript
- An [experimental new framework for structuring Wii U/3DS web applications](https://github.com/PretendoNetwork/Yeah/pull/1) is being worked on. This framework is intended to help modernize the development/workflow of Juxtaposition, making it feel more like a modern web application built with frameworks like [Nuxt](http://nuxt.com/)/[Next](https://nextjs.org/). However this should be usable by anyone wanting to make a web application compatible with the Wii U/3DS
## Juxtaposition on Cemu
While not something we completed ourselves, we felt this to be news worthy enough to be included here. Back in 2023, I began looking into getting the Wii U Miiverse app to run in Cemu. Doing so would solve a pretty big pain-point: lack of a full functional web version of Juxtaposition. We do have a read-only website available right now, however it needs some UI updates and lacks the ability to create posts.
With a few tweaks to Cemu, some patched system files, and a couple of server-side patches, I was able to get the [Miiverse app to load without much issue](https://github.com/PretendoNetwork/Martini/issues/13#issuecomment-2544470882). However there were a number of issues with my approach, namely the fact that it required patched system files. Due to these issues, I shelved the idea indefinitely, telling myself I would pick it back up eventually.
Thanks to the dedicated work by developer [Arian Kordi](https://github.com/ariankordi), Cemu now has the ability to [launch the Miiverse app into Juxtaposition](https://github.com/cemu-project/Cemu/pull/1747) without ANY patched system files! This has not yet made it into an official Cemu release, however the changes have been merged and can be used today if compiled manually.
# Game Servers
While the last few months had a lot of focus on internal changes and Juxtaposition, game servers also saw a lot of attention!
- [Dani](https://github.com/DaniElectra) has begun implementing the [`MessageDelivery` and `Messaging` protocols into our "common" module](https://github.com/PretendoNetwork/nex-protocols-common-go/pull/54). Once complete, these protocols should be widely available to all games
- [Dani](https://github.com/DaniElectra) Has begun [implementing the `MatchmakeExtension::GetPlayingSession`](https://github.com/PretendoNetwork/nex-protocols-common-go/pull/55) NEX method for use in multiplayer games
![The Lobby area in Splatoon 1.](/assets/images/blogposts/december-25-2025/image6.png)
*Splatoon, for its part, calls GetPlayingSession every time you enter the multiplayer lobby.*
- [Trace](https://github.com/TraceEntertains) updated [Yo Kai Watch Blasters](https://github.com/PretendoNetwork/yo-kai-watch-blasters/pull/5) to the latest server libraries, including the above mentioned changes by [Dani](https://github.com/DaniElectra). With this update friend rooms and trading are now functional
- A proposal for updating several areas of state tracking in our underlying PRUDP server [has been created](https://github.com/PretendoNetwork/nex-go/issues/87)
- Puyo Puyo Tetris neared completion, with replay upload and club matchmaking - which previously didn’t work - now implemented. There’s one issue left where you can’t always see other people’s replays.
![The Replay area in Puyo Puyo Tetris (WiiU), showing a single replay of a battle between Imora and skweed.](/assets/images/blogposts/december-25-2025/image9.png)
*There should be more than one replay listed here. Still, one is better than before!*
## Super Smash Bros. 4
Ever since the games launch, Super Smash Bros. 4 has had an issue where only one lobby can be active at a time for a given game mode. This has been often dubbed the “One True Lobby” bug. Trying to fix this bug has been a priority, and we are happy to announce that we now understand why the bug occurs.
When a client wants to join a multiplayer game, it has 2 options to do so:
1. Searching (internally called “browsing”) for active sessions to join manually
2. “Auto matchmaking”, which automatically puts you into a session
In both options, the client sends the server various details about the kind of session it wants (called [“search criteria”](https://nintendo-wiki.pretendo.network/docs/nex/protocols/match-making/types#matchmakesessionsearchcriteria-structure)) and the various settings/capabilities of the game (such as how many players are joining). If no active sessions exist that match what the client wants/needs, the server creates a new one for the client and automatically assigns them as the host/owner.
The key difference between the 2 matchmaking functions is that “browsing” can return a list of candidate sessions the client can pick from manually, whereas the “auto matchmaking” functions will always automatically join and return the 1st session possible, without user input.
The “One True Lobby” bug occurs due to a previous misunderstanding of 2 of the search criteria settings:
- `m_VacantOnly`
- `m_VacantParticipants`
Through past testing prior to the official servers shutdowns, we knew that these 2 settings controlled whether or not sessions should be considered “invalid” for joining based on the number of current participants. The `m_VacantOnly` controlling whether or sessions with full lobbies are valid, and `m_VacantParticipants` controlling the number of empty slots in the session.
Previously, we misunderstood in which contexts these settings are actually used, and when to ignore them. The `m_VacantOnly` setting has always existed (since NEX v1), however the `m_VacantParticipants` setting was added 2 major and 4 minor versions later (in NEX v3.4). Due to this, it seemed like `m_VacantParticipants` *replaced* the original `m_VacantOnly` setting. We also believed that these settings were treated the same in both matchmaking functions.
We now know this to be incorrect. In reality, `m_VacantOnly` and `m_VacantParticipants` are both still used. `m_VacantOnly` is also only used when using the “browsing” matchmaking function, whereas `m_VacantParticipants` is used in all functions. Logically, this also makes sense. Allowing a game client to see full lobbies may be useful in certain contexts, but would not be needed when “auto” matchmaking, whereas checking the number `m_VacantParticipants` *is* required at all times.
This was confirmed through a mix of previous testing/notes, and by decompiling various titles to inspect their implementations. These decompilation efforts also extend past the Wii U/3DS, as NEX is used in various Switch titles as well, and NEX itself is based on an existing library known as Rendez-Vous which is seen in many non-Nintendo titles. This fix for Super Smash Bros. 4 was helped by decompiling Splatoon 2 on the Switch, as it was the only game we could find that still implemented a mix of both `m_VacantOnly` and `m_VacantParticipants` being used at the same time (confirming that one did not replace the other), highlighting how important research is to improving accuracy and why certain updates may take more time than others.
A temporary fix for the bug is already deployed to production, while a [proper implementation is currently in the works](https://github.com/PretendoNetwork/nex-protocols-common-go/pull/59).
![A screenshot with 3 instances of Cemu and an IDE window. Two of the Cemus are in a battle in Smash 4, while the third is in an empty lobby.](/assets/images/blogposts/december-25-2025/image7.png)
*Image demonstrates 2 lobbies active in 1v1 mode, with 3 users!*
# 3rd Party Integrations
Historically, there has always been some confusion as to what the goals/scope of the project actually are. This is not helped by Nintendo’s often confusing branding of “Nintendo Network” on certain games. Many people, understandably, assume that our goal is to provide servers for *all* games on the Wii U/3DS. This is, in fact, not the case. Our scope has always been limited to supporting games which use Nintendo’s 1st-party networking library called NEX. At times, we may provide replacement servers for games whose original servers are trivial to implement, but that is not the standard we hold ourselves to. Those are exceptions. If a game did not use NEX, it should always be assumed that we will not provide servers for it.
This confusion often comes from a mixture of word-of-mouth rumors, and due to Nintendo’s questionable Nintendo Network branding/developer usage, especially in relation to the name we chose for the project. All games which have any online capabilities and/or make use of your system/network account are branded with the Nintendo Network logo, *even if that game uses its own online servers*. This is because all games on the Wii U/3DS first must go through Nintendo’s own account servers for account/device authentication (this server is called NASC on the 3DS when not using a NNID, and NNAS when using a NNID on either console). These account servers authenticate your device/account and then issue the game tokens that can be used to identify the user. After this initial authentication, the developer is *free to do anything they wish* with the game. However, since the game DID use Nintendo’s account servers, the game receives the “Nintendo Network” branding.
Games such as WATCH_DOGS are prime examples of this. They authenticate your NNID, get the identity tokens, and then use those tokens to link your NNID to your Uplay (now Ubisoft Connect) account. After that, the game uses servers entirely ran by Ubisoft for games *actual* online features.
These games are *not* within our projects scope, and we have always felt that the best course of action was to leave those games to their own dedicated teams to revive, as they often require expertise specific to said games which we do not have, and do not wish to add onto our ever growing work load.
That being said, it has always been difficult to accomplish this without potential fragmentation in the community. How could someone make their own WATCH_DOGS servers without an accessible NNAS server, and while ours does not support the game? Requiring these 3rd party teams to run portions of the Nintendo Network infrastructure adds unnecessary load onto them and potentially creates fragmentation in the community.
Because of this obvious issue, we are excited to announce that we have begun the process of allowing 3rd parties to register themselves with us, and providing tools for them to use to officially integrate into Pretendo Network *the exact same way Nintendo did*! Right now we are still in the planning stages, but once completed anyone making servers for games that are out of our scope (or even stand-alone applications that wish to integrate with our services), will be able to do so seamlessly.
For details on how 3rd parties operated officially, and for our current plans to support them ourselves, see [this GitHub feature request](https://github.com/PretendoNetwork/account/issues/202).

79
content/blog/6-2-25.md Normal file
View File

@@ -0,0 +1,79 @@
---
title: "May Progress Update"
author: "Jon"
author_image: "https://www.github.com/jonbarrow.png"
date: "June 2, 2025"
caption: "Updates covering the first half of the year"
cover_image: "/assets/images/blogposts/6-2-25.jpg"
---
Hey all, Jon here! We know it's been quite a while since our last blog post. We planned to get these out more often, but alas more important issues and updates came first. We apologize for the lack of blog posts, and promise to get them out as often as we can. With that, halfway into the year seems like as good a time as any to summarize what we've been up to!
(Note: This blog post will not cover *all* changes made since the last post, as there are far too many to list. We will be highlighting the more relevant/larger ones here)
# Technical Updates
Many of you voted to have more technical updates in blog posts from now on, and today marks the first time we do!
## Splatoon Database Performance
Around May 26th, 2025 we noticed random instability in Splatoon. The game would work for a while, allowing players to create new, and join existing, matches, before seemingly randomly locking up. This locking up would cause subsequent requests to never get a response from the server, resulting in failed connections. Developers [shutterbug](https://github.com/shutterbug2000) and [quarky](https://github.com/ashquarky) quickly began investigating. We were unsure where the issue was at, but we had a pretty good idea of where to look. The locks could be happening in 2 places:
1. The application layer. A few examples being:
1. A locked [mutex](https://en.wikipedia.org/wiki/Lock_(computer_science)) which never releases. Our servers are written in [Go](https://go.dev/), and make use of [goroutines](https://go.dev/doc/effective_go#goroutines) for concurrency. Primitive Go types such as [slices](https://go.dev/doc/effective_go#slices) and [maps](https://go.dev/doc/effective_go#maps) can only be accessed by one goroutine at a time. To ensure this, a mutex is used to lock access when a goroutine needs the data, and is released when it's done with it. If a goroutine were to lock up and never release the mutex, then future goroutines will never be able to access it, and also be locked up waiting for the mutex to release.
2. A poorly structured SQL query could lock up the database connection at the application layer, causing future requests to no longer be able to access the database.
2. The database layer. A few examples being:
1. Database corruption could lead to queries failing or getting stuck, locking up the connection.
2. Poor indexing causing full table scans on massive tables, locking up the connection.
3. Bad queries causing the table to infinitely loop and lookup in itself, locking up the connection.
Shutter began by checking the code for locked mutexes and the server logs for any abnormalities. Our game server libraries are split into 3 separate modules, one of which we colloquially refer to as ["common"](https://github.com/PretendoNetwork/nex-protocols-common-go). This module holds all the "common" default implementations of features used by many games. Quarky began by investigating the database itself. Together, they were able to narrow down the problem areas to 2 functions. Lockups would happen in the [`MatchmakeExtension::AutoMatchmake_Postpone`](https://github.com/PretendoNetwork/nex-protocols-common-go/blob/50586821d228cdc2bae728797febdae51e67fe5b/matchmake-extension/auto_matchmake_postpone.go) and [`MatchMaking::UnregisterGathering`](https://github.com/PretendoNetwork/nex-protocols-common-go/blob/50586821d228cdc2bae728797febdae51e67fe5b/match-making/unregister_gathering.go) functions. These functions are responsible for creating/joining multiplayer sessions, and for deleting them when the game is over.
There did not appear to be any areas where a mutex would not release, so we switched our attention back to the database itself. We had noticed some wonky behavior from the database earlier as well, later fixed by [Will](https://github.com/binaryoverload), and I had a hunch that this is where the issue would lie as well. Upon investigation, we found several instances of poor database performance, such as a lack of indexes on some "hot spots" resulting in slower queries. Most notably, we found 2 queries that had become locked, running over 7 and 9 hours respectively. These queries are what was causing the database to lock up, and requests to not get responses. But we still didn't quite know WHY they were locking. It was not initially clear if the issue was due to a looping query, poor indexes, or database corruption. The database in question only held ephemeral data about temporary matches, however, so we opted to just rebuild the database and add in the missing indexes at the same time. Doing so would cover both possibilities of database corruption and missing queries causing the locks, and so far things have once again become stable.
During the investigation I also noticed a lack of a proper timeout mechanism in the Go functions that made the database queries. Regardless of the reason for *why* the queries locked up, having a timeout would prevent things from looping *forever*.
This investigation has highlighted some key areas of improvement in regards to our database performance, and we have already begun investigating using even better indexes (currently being tested in Minecraft) and will begin to implement proper query timeouts. So while it is unfortunate that Splatoon was down, in the end this will result in even better performance moving forward.
## `DataStore` Protocol Rework
As mentioned above, many games share a "common" implementation of certain features. This allows us to define this functionality once and simply tell a server to use it. In the past, our philosophy was to be as unopinionated as possible in this regard, only implementing basic boilerplate for the functions and providing developers a series of configurations and hooks to use. The actual *logic* of the functions was still up to the developers to set. This was done so that developers outside of our team could more easily integrate our code into their systems, by just hooking up whatever stack they already use.
We have recognized the limitations of this approach however, and have decided to become more opinionated. This first took place in the matchmaking code, made by [Dani](https://github.com/DaniElectra), making it so that all the logic for matchmaking now lives in our "common" module. This now allows our code to be more "plug-and-play", simply telling servers to use matchmaking and letting our logic do the rest.
Another protocol which used this unopinionated philosophy was our [`DataStore`](https://nintendo-wiki.pretendo.network/docs/nex/protocols/datastore) implementation. `DataStore` is a protocol developed by Nintendo allowing for "object" (file) storage in games, essentially acting as a frontend for [S3](https://en.wikipedia.org/wiki/Amazon_S3). This protocol is what powers games like Super Mario Maker (courses are "objects"), Animal Crossing: New Leaf (dreams are "objects"), Mario vs. Donkey Kong: Tipping Stars (levels are "objects"), and more.
We have now begun the process of moving our `DataStore` implementation into a more opinionated implementation, allowing for the same sort of "plug-and-play" nature as seen in the matchmaking changes. Progress can be seen [here](https://github.com/PretendoNetwork/nex-protocols-common-go/pull/53). Once finished, this will be our first *fully complete* protocol implementation, allowing for MANY games to get their "object" features working without any extra work. This is also why Mario vs. Donkey Kong: Tipping Stars is still offline, it is so old that it needs to be rewritten from the ground up and is mostly just `DataStore`, making it the perfect candidate to test these new changes against.
Eventually we hope to do this with *all* protocols in the future.
# New Games/Updates
Several new games have joined us since our last blog post! Both existing games coming out of beta, and entirely new games!
Also a big thank you to everyone outside of our team as well for helping debug and suggest changes!
## Splatoon
As a belated celebration for Splatoon's 10th anniversary (we deeply apologize that the stability issues mentioned above prevented us from doing anything on time), for the next round of rotations (starting June 7th) our rotations will feature previously banned stages! Allowing banned stages has been a highly requested feature for a long time, so we felt this was a good time to try it out!
## Animal Crossing: New Leaf
Thanks to the work by [shoginyan](https://github.com/shoginyan) and [shutterbug](https://github.com/shutterbug2000), Animal Crossing: New Leaf has officially left beta testing and is available to everyone! Note that Dream Suite is not yet implemented (see [`DataStore` Protocol Rework](#datastore-protocol-rework)), but multiplayer is supported! We've also identified an issue regarding best-friend messages, of which a fix is being actively tested.
## Mario Kart 7 Communities
Mario Kart 7 now has partial support for communities! Leaderboards are not currently implemented, as Mario Kart 7 uses a version of the [`Ranking`](https://nintendo-wiki.pretendo.network/docs/nex/protocols/ranking/legacy) that is very different to the one used by modern games.
## Yo-kai Watch 2 and Yo-kai Watch Blasters
[shoginyan](https://github.com/shoginyan) has also kick-started Yo-kai Watch 2 and Yo-kai Watch Blasters both into development! Yo-kai Watch 2 has left beta and is available to everyone, while Yo-kai Watch Blasters (and variants) is currently in beta testing.
## Monster Hunter 4 Ultimate
Monster Hunter 4 Ultimate has officially left beta testing! We have also removed the region lock, allowing for experimental crossplay between MH4U and MH4G players! You may encounter technical difficulties when playing across regions due to this experimentation, so please report any issues you encounter to [the game's issue tracker](https://github.com/PretendoNetwork/monster-hunter-4-ultimate/issues/new/choose).
## Swapdoodle
Swapdoodle was one of the first titles Dani wanted to work on, prior to him joining our core dev team. After joining, focus was shifted elsewhere and work stopped on Swapdoodle fairly early. However thanks to the work by outside contributors [Silver-Volt4](https://github.com/Silver-Volt4) and [CenTdemeern1](https://github.com/CenTdemeern1), work on Swapdoodle has once again picked up! They took it upon themselves to implement the server entirely, with promising results! For more information, see:
- https://forum.pretendo.network/t/we-implemented-swapdoodle-and-would-like-to-contribute-it/16204
- https://github.com/PretendoNetwork/swapdoodle/pull/1
## Dr. Luigi and Dr. Mario: Miracle Cure
Both Dr. Luigi and Dr. Mario: Miracle Cure have officially left beta testing! Both titles are now available to the public!
## The Legend of Zelda: Tri Force Heroes
After several months of downtime, The Legend of Zelda: Tri Force Heroes is officially back online! This was one of our legacy games requiring upgrades to our latest libraries, and has finally had its issues ironed out. Due to some recent changes to our general matchmaking code, the games multiplayer region lock was unintentionally returned. This is being looked into and should be fixed in due time.

54
content/blog/7-17-26.md Normal file
View File

@@ -0,0 +1,54 @@
---
title: "July 15 security incident"
author: "Dani"
author_image: "https://www.github.com/DaniElectra.png"
date: "July 17, 2026"
caption: "What happened and what we are doing to prevent this from happening again"
cover_image: "/assets/images/blogposts/7-17-26.webp"
---
Hi everyone. We are unfortunate to tell you that we have experienced a security incident. I didn't expect this to be my first blog post, but we want to disclose what happened before, during and after the unplanned maintenance and what we are doing to improve our security and prevent this incident from happening again.
Before starting, we want to assure everyone that **no passwords, console or payment information has been leaked**, and an email will be sent to all potential victims about their account security.
## What happened
On July 15, we received a report about an exploit that a user was using to seemingly reset anybody's account password and get access into it. Given the danger of the exploit if it were true, we decided to take down the servers while we investigated into the claims of the report and the damage they could have done.
The evidence from the report showed an attempt of a ["padding oracle"-style attack](https://en.wikipedia.org/wiki/Padding_oracle_attack) against our tokens to trigger a password reset. I'll explain what that means in layman's terms:
When you login with your username (in our case the PNID) and password, the server gives your web browser or your console a **"token"**, which is a number that identifies that specific session in your device. You don't want to store any sensitive data there for anyone to see, or worse, you don't want to make the token simple, otherwise anyone would be able to *guess* a token and pretend to be you.
To prevent this, our tokens (up until today) only had basic information like the account ID (called **PID**) to identify you, and the purpose of the token. This data would be encrypted to prevent anyone from getting this data or replace it to disguise as another person. However, there is still the possibility of doing a "padding-oracle" attack which allows you to effectively guess and try to replace the PID with a different one, letting the attacker temporary access into the account, which they could protect with a password reset.
## Impact
During the investigation, we saw activity that correlated with someone attempting this attack thousands of times starting on July 9, and according to our records, 1864 password resets were triggered on that timeframe (note that not all of those resets are necessarily compromised accounts, that number includes legitimate resets). This is a small fraction of the userbase (about 0.3% of all PNIDs).
We haven't seen any evidence of data exfiltration from our databases. However, with a compromised account, the attacker *may* have also had access to detailed information of the PNID, though this data is generally already public:
- Access level: whether you have tester access or the account is banned
- Account creation and updated date
- PNID and PID
- Birth date
- Gender: this is usually already public with your Mii
- Country and timezone: these are technically already public if you have played online, since many games show this information to others and on multiplayer your IP address has to be made available to other players
- Email address
- Discord user ID: if you have Discord linked
- Basic tier level data: whether you have Mario or Super Mario perks
**Once again, we want to reiterate that no passwords, console or payment information has been leaked.** The payment information is managed exclusively by Stripe, our payment processor, so we don't have any access into it. And in any case, we store secure password hashes so hackers can't recover the password had those hashes gotten leaked **(which they haven't)**.
## What we're doing
Regarding the compromised accounts, while passwords were not leaked, as a precaution we will be forcing a mandatory password reset to all potentially affected users by changing the passwords to random ones. Alongside that, we will restore the previous emails of the accounts in the cases that it got changed (which was only 7 people). We will notify all possible victims about these measures via email too.
We are also making improvements on the technical side to prevent this from happening anymore. Oracle attacks work by manipulating unauthenticated encrypted data (which was our case, as the Wii U/3DS impose limits on how large certain tokens may be). As we explained we were storing some metadata about the user in the token for consuming services to use (this is also what Nintendo did with their tokens), but even prior to this incident we knew that this system would not work long term and were already planning to phase it out.
The [new system](https://github.com/PretendoNetwork/account/pull/313) which we have migrated to embeds no data inside tokens, and instead uses completely random (opaque) data, and require services to instead always phone back home to get the data that would normally be inside the tokens. The size of the new tokens, along with them cryptographically secure random byte, are functionally impossible to brute force or tamper with, rendering the attack useless.
Some of you may have thought about implementing two-factor authentication (2FA) into our services to improve security. But as promising as that sounds at first, it is much harder to implement within the limitations of the consoles, as the 3DS and Wii U have never supported it. There has been discussion about potential solutions to mitigate this, but it will take time before those ideas come into life.
## Closing
We want to apologise to everyone who has been affected by this incident, whether it be for being a victim of the attack or by our maintenance period. And also give my thanks to the rest of the team who has been working on this maintenance to get our servers out as soon as possible, or handling moderation in our platforms during the incident. I hope our next blog post goes on a more positive note.

View File

@@ -1,7 +1,7 @@
---
title: "Test"
author: "limes.pink"
author_image: "https://github.com/gitlimes.png"
author_image: "https://github.com/limes.pink.png"
date: "January 20, 2038"
caption: "A post to test the styling of the various elements we might use"
cover_image: "https://media.discordapp.net/attachments/413884110667251722/886474243662037062/image1.jpg"
@@ -35,23 +35,23 @@ _italic_
---
| Element | Description |
| :----------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| table | The table HTML element represents tabular data — that is, information presented in a two-dimensional table comprised of rows and columns of cells containing data. |
| tuble | The tuble HTML element represents tubular data — that is, information presented in a totally gnarly and radical way. |
| table | A table is an item of furniture with a flat top and one or more legs, used as a surface for working at, eating from or on which to place things. |
| Element | Description |
| :------ | :----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| table | The table HTML element represents tabular data — that is, information presented in a two-dimensional table comprised of rows and columns of cells containing data. |
| tuble | The tuble HTML element represents tubular data — that is, information presented in a totally gnarly and radical way. |
| table | A table is an item of furniture with a flat top and one or more legs, used as a surface for working at, eating from or on which to place things. |
| Element | Description |
| ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| table | The table HTML element represents tabular data — that is, information presented in a two-dimensional table comprised of rows and columns of cells containing data. |
| tuble | The tuble HTML element represents tubular data — that is, information presented in a totally gnarly and radical way. |
| table | A table is an item of furniture with a flat top and one or more legs, used as a surface for working at, eating from or on which to place things. |
| Element | Description |
| ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| table | The table HTML element represents tabular data — that is, information presented in a two-dimensional table comprised of rows and columns of cells containing data. |
| tuble | The tuble HTML element represents tubular data — that is, information presented in a totally gnarly and radical way. |
| table | A table is an item of furniture with a flat top and one or more legs, used as a surface for working at, eating from or on which to place things. |
| Element | Description |
| -----------: | -----------------------------------------------------------------------------------------------------------------------------------------------------------------: |
| table | The table HTML element represents tabular data — that is, information presented in a two-dimensional table comprised of rows and columns of cells containing data. |
| tuble | The tuble HTML element represents tubular data — that is, information presented in a totally gnarly and radical way. |
| table | A table is an item of furniture with a flat top and one or more legs, used as a surface for working at, eating from or on which to place things. |
| Element | Description |
| ------: | -----------------------------------------------------------------------------------------------------------------------------------------------------------------: |
| table | The table HTML element represents tabular data — that is, information presented in a two-dimensional table comprised of rows and columns of cells containing data. |
| tuble | The tuble HTML element represents tubular data — that is, information presented in a totally gnarly and radical way. |
| table | A table is an item of furniture with a flat top and one or more legs, used as a surface for working at, eating from or on which to place things. |
Yee haw 🤠