Skip to content

API: authentication

Kettle :~) edited this page Oct 4, 2024 · 3 revisions

The authentication server is best accessed at https://platypuss.net, although the beta site will usually also work. Besides serving the Platypuss website it's also responsible for keeping track of accounts and authentication across the service. It stores the email address, username and about-me for each account on the platform, as well as a hash of the password (the password itself never leaves the client in plain text form). This page will outline the various URLs you can access on the website to do certain things.

Logging In

/login

Creating an account and signing in is handled by way of an HTTP POST request to https://platypuss.net/login, with the body of the request a JSON representation of an object with these properties:

  • createNew: boolean, false if we're logging into an existing account, true if we're trying to create a new one.
  • email: string, the email address of the account if logging in and the address to send a verification email to if creating a new one.
  • password: string, the password hashed in a method outlined below.
  • server: string, deprecated, defaults to "example.com".

The server will respond with a JSON object, containing some fields:

  • alreadyExists: boolean, true if an account with that email address existed before the request was sent, false otherwise.
  • passwordMatches: boolean, undefined if createNew was true as there's no password to compare it against, otherwise true if the password was correct and false if it was incorrect.
  • sessionID: string, a session token that can be used for other authentication-related requests.

/requestAccountRecovery

The other way to log into an account is by sending a GET request to /requestAccountRecovery?accountEmailAddress=<address>. This will send an email to the address provided containing a link to let them them sign into their Platypuss account without needing to type in their password.

Session and user-related information

/sessionInfo

To find out information about a session you can send a GET request to /sessionInfo?id=<session token>, and you'll get a JSON object of this structure in response:

  • creationTime: integer, epoch time when the session was created.
  • server: string, the server the session is valid for.
  • userID: string, the ID of the user for whom the session is valid.
  • id: string, the ID of the session itself.

/userInfo

This is a similar deal except you can use either the ID of the user or of any session valid for them. You'll get a response like this:

  • username: the "display name" of the user.
  • avatar: the URL of the user's profile picture / avatar. It's usually a relative URL to the root of the platypuss.net domain.
  • id: the ID of the user.
  • aboutMe: a section of the user's profile that they can customise themselves with Markdown.
    • aboutMe.text: the Markdown text of their about me section.
  • tag: an unique tag given to the user that's short and easily memorable and can be used to tell between impostors, as well as potentially some other features in the future.

/getServerTokens

If you send a GET request to /getServerTokens?id=<session token> you will get the following JSON object in return:

  • servers: key/value map where each key contains the domain name and port, the invite code and the subserver (if applicable) for each of the servers the user is in, separated by spaces, and the value is an unique session token for that specific server so that the owner of one server can't "log in" as that user on another server, or access/modify account information they shouldn't be able to.
  • userID: string, the ID of the user for whom the session token is valid
  • blockedUsers: Array of strings, contains IDs of any users they have chosen to block, not currently used but reserved for future use.
  • friends: Similar to blockedUsers, also not used but reserved for in the future.

Server-related operations

/leaveServer

Send a GET request to /leaveServer?id=<session token>&ip=<server info> to leave a server, where <server info> is a space separated list of the domain name or IP address and port of the server, the invite code and the subserver if applicable.

/joinServer

Same thing as above with /leaveServer except it's /joinServer?id=<session token>&ip=<server info> and it's used to join a server rather than leave it.

Changing account information

/pfpUpload

Send a POST request to /pfpUpload?id=<session token>&type=<filetype> where the body of the request is image data to set that image as the profile picture / avatar of the user. The maximum permitted file size is 10MB. The <filetype> parameter specifies the type of image to use, either as a MIME type or common file extension.

/editAboutMe

Send a POST request to /editAboutMe?id=<session token> where the body of the request is a JSON object to change the user's about me section. The JSON object should contain a text field with markdown text to use for the about me section. This can't be more than 2000 characters long.

/changeUsername

Send a GET request to /changeUsername?id=<session token>&newUsername=<new username> to change the user's username to the value of <new username>.

/changePassword

Send a GET request to /changePassword?id=<session token>&newPassword=<new password> to change the user's password to the value of <new password>. The password should be hashed using the method outlined below.

/deleteAccount

Send a GET request to /deleteAccount?id=<session token> to delete the user's account.

/randomsand.wav

Send a GET request to /randomsand.wav to get a friendly Undertale noise in response.

How passwords should be hashed

Passwords should be hashed using the same method to ensure regardless of what client they use people can still log into their account. The JavaScript code is below, and the same method should work when implemented in other languages.

function hashPassword (str, seed = 20) {
    let h1 = 0xdeadbeef ^ seed,
    h2 = 0x41c6ce57 ^ seed;
    for (let i = 0, ch; i < str.length; i++) {
        ch = str.charCodeAt(i);
        // Math.imul multiplies without loss of precision
        h1 = Math.imul(h1 ^ ch, 2654435761);
        h2 = Math.imul(h2 ^ ch, 1597334677);
    }
    h1 = Math.imul(h1 ^ (h1 >>> 16), 2246822507) ^ Math.imul(h2 ^ (h2 >>> 13), 3266489909);
    h2 = Math.imul(h2 ^ (h2 >>> 16), 2246822507) ^ Math.imul(h1 ^ (h1 >>> 13), 3266489909);
    return (h2>>>0).toString(16).padStart(8,0)+(h1>>>0).toString(16).padStart(8,0);
};

I originally got this code off this Stackoverflow post.