Neopets Mobile: Difference between revisions

From Computers Wiki
Jump to navigationJump to search
(→‎Responses: Add rejected details)
 
(43 intermediate revisions by the same user not shown)
Line 15: Line 15:
The META-INF/MANIFEST.MF for the Nokia 6280 version specifies a Java version of 1.4.2_04.
The META-INF/MANIFEST.MF for the Nokia 6280 version specifies a Java version of 1.4.2_04.


The decompiler used is quiltflower: https://github.com/QuiltMC/quiltflower
The decompiler used is quiltflower: https://github.com/QuiltMC/quiltflower and the javax.microedition classes were copied from https://github.com/mcpat/java-microedition-libraries

=== Nokia 6280 V02.30.00 (en) Singtel ===

<code>m.java</code> contains two calls:
* http://npprod-singtel.in-fusio.com/data-np/
* http://npprod-singtel.in-fusio.com/singtel/check?session= ''followed by RecordStore.openRecordStore("data-i", true).getRecord(1) as a String if not null, else ""''

The session check appears to return one of the following values, with anything else as a failure code of -1:

{| class="wikitable"
! Response !! Treated as ID
|-
| SUBSCRIBED || 1
|-
| UNSUBSCRIBED || 2
|-
| REVOKED || 3
|-
| SECURITY || 5
|}

=== Nokia 6111 ===

<code>m.java</code> contains one call:
* http://npprod.in-fusio.com/data-np/

== Getting sample network requests ==

# Install Kahvibreak
# Edit <code>/path/to/Kahvibreak/Software/win32/KLaunch.bat</code>
# Change <code>echo NetworkNotAvailable=true>>property.txt</code> to <code>echo NetworkNotAvailable=false>>property.txt</code>
# Edit <code>/etc/hosts</code>
# Add <code>127.0.0.1 npprod-singtel.in-fusio.com</code>
# Add <code>127.0.0.1 npprod.in-fusio.com</code>
# Run something on port 80 that listens to <code>/data-np/</code>
# Launch Neopets Mobile from Kahvibreak
# Try to login

== Reverse engineering the format ==

I've been renaming symbols in the decompiled source code to slowly figure out what the application is looking for as a response.

The response seems to use the same data structure as the request: a form-encoded set of key-value pairs, then a newline, then some sort of binary data structure.

Numbers are big-endian. Strings are delayed until the end of the structure. However, a reference to a string may appear in the number buffer as a short representing the offset in the string buffer to the start of the string. The start of the string is a short representing the length of the string, followed by the text of the string itself. Note that the first item in the number buffer will always be a pointer to the encoding information string in the string buffer, which itself is the first item of the string buffer.

Nested structures can also be in the string buffer. They are handled similarly: the number buffer contains the offset to the start of the nested structure in the string buffer. However, the nested structure does not have its first six bytes, and the meaning of the "number buffer len + 2 (n)" field is changed to "number of items in this structure".

The game ID is hardcoded to 11061 and the center is hardcoded to 61.

After the form data and newline, the structured data looks like this:

{| class="wikitable"
! Offset !! Type || Meaning
|-
| 0 || short || Tag
|-
| 2 || int || Length-derived value: 8 * (2 + n + m)
|-
| 6 || short || number buffer len + 2 (n)
|-
| 8 || bytes || number buffer
|-
| n + 8 || bytes || string buffer
|-
| m || byte || 0xFF, end of structured data
|}

For example, the login attempt above can be broken into the following parts:

{'client': 'NEOPETS/2.8', 'game': '11061', 'center': '61', 'language': 'en'}
Tag: 40961 (a001)
Number buffer: b'\x00\x00\x00\x00\x00@\x00\x00\x00@\x00\x10\x00\x18\x00 '
String buffer: b'\x00\x0eISO-8859-1;2.8\x00\x06adadad\x00\x06gjgjgj\x00\x00\x00'

Note that if tag == 0x8000 or 0x8064, a different format is followed:

{| class="wikitable"
! Offset !! Type !! Meaning
|-
| 0 || short || Tag
|-
| 2 || int || (len(message) + 1) * 8
|-
| 6 || byte || 0x00, start of message
|-
| 7 || string || error message to display in console
|}

The application emits the following request tags:
* 33022 (test writing numbers)
* 40961 (login)
* 40963 (write state)
* 40965 (login + ?)
* 40967 (create pet + create account)
* 40968 (create pet)
* 40969 (add item)
* 40971 (test writing strings)
* 40973 (request unlock info)

The application handles the following response tags:
* 40960 (sync status)
* 40962 (user info)
* 40964 (does nothing)
* 40966 (rejected username, password, or pet name)
* 40970 (info about added item)
* 40972 (does nothing)
* 40974 (unlock info)

== Subgame IDs ==

Each subgame has a number of times it can be played (or score submitted) each day.

* 21: Lutari Savings Bank
* 22: Island Market
* 23: Bog of Charity
* 24: Wheel of Happiness
* 25: Survival Academy
* 26: Fluorescent Pools
* 27: Blockstravaganza!
* 28: Go Go Lutari!

== NeoFriend flag IDs ==

Bit IDs start at 0, with the least significant bit being 0.

* 8: Outgoing Neomail not synchronized?
* 9: Accepted invitation since last check?
* 10: Always set?
* 11: Invitation already sent
* 12: Registered for Neopets Mobile
* 13: Neopets Mobile message pending?

== Requests ==

=== Test writing numbers (33022) ===

Number buffer contains:
* pointer to encoding string
* constant int 0x0
* boolean hardcoded to true

=== Logging in (40961, 40965) ===

With username "adadad" and password "gjgjgj", in Python 3 bytes notation:

b'client=NEOPETS/2.8&game=11061&center=61&language=en\n\xa0\x01\x00\x00\x01\xa0\x00\x12\x00\x00\x00\x00\x00@\x00\x00\x00@\x00\x10\x00\x18\x00 \x00\x0eISO-8859-1;2.8\x00\x06adadad\x00\x06gjgjgj\x00\x00\x00\xff'

Number buffer contents:
* pointer to encoding string
* constant int 0x64, doesn't mean anything
* constant int 0x64, doesn't mean anything
* pointer to username string
* pointer to password string
* pointer to extraneous information string; seemingly usually a zero-length string

I don't know how 40965 semantically differs from the first one.

=== Creating a pet and signing up (40967, 40968) ===

With username "adadad", password "gjgjgj", male green Kacheek, name "cccccc", birthday 1999-12-31, health 6, strength weak, defense very poor, movement slow, height 36 cms, weight 26 lbs, in Python 3 bytes notation:

b'client=NEOPETS/2.8&game=11061&center=61&language=en\n\xa0\x07\x00\x00\x04\xd0\x00:\x00\x00\x00\x00\x00@\x00\x00\x00@\x00\x10\x00\x18\x00 \x00(\x004\x00:\x00>\x00B\x00J\x00S\x00Z\x00\x00\x00\x06\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x05\x00\x00\x00$\x00\x00\x00\x1a\x00\x0eISO-8859-1;2.8\x00\x06adadad\x00\x06gjgjgj\x00\x06cccccc\x00\n1999-12-31\x00\x04Male\x00\x02en\x00\x02EN\x00\x06adadad\x00\x07Kacheek\x00\x05GREEN\x00\x04Male\x00\xff'

Number buffer contents:
* pointer to encoding string
* constant int 0x64, doesn't mean anything
* constant int 0x64, doesn't mean anything
* pointer to username string
* pointer to password string
* pointer to pet name
* if 40967, pointer to date of birth string (YYYY-MM-DD)
* if 40967, pointer to gender string (Male, Female)
* if 40967, pointer to lowercase language string (en)
* if 40967, pointer to uppercase language string (EN)
* if 40967, pointer to username string again
* pointer to species string (Kacheek, Kougra, Shoyru, Lutari)
* pointer to colour string (GREEN, RED, YELLOW, BLUE)
* pointer to gender string again
* int pet health
* int pet strength
* int pet defense
* int pet movement
* int pet height
* int pet weight

=== Add item to inventory (40969) ===

Number buffer contents:
* pointer to encoding string
* constant int 0x64, doesn't mean anything
* constant int 0x64, doesn't mean anything
* pointer to username string
* pointer to password string
* pointer to extraneous information string; seemingly usually a zero-length string
* int mobile item ID, which does not appear to be the same as the website item ID

=== Test writing strings (40971) ===

Number buffer contents:
* pointer to encoding string
* pointer to an arbitrary string
* pointer to "Check this out!"
* pointer to "+33612345678"

=== Request unlock info (40973) ===

Number buffer contents:
* pointer to encoding string

That's it.

== Responses ==

=== Synchronization status (40960) ===

A break statement is missing after this in the application, but the next case throws an exception that is immediately swallowed, so everything is OK.

Number buffer contents:
* pointer to encoding string
* int with sync status ID

Known sync status IDs:
* 41: Already running a mobile game session

=== User info (40962) ===

Number buffer contents:
* pointer to encoding string
* int unused
* int unused
* pointer to unused string
* int user referral status; if <code>>> 31 & 1 == 1</code>, user ''maybe'' clicked a referral link?
* int neopoints
* pointer to Island Gossip string
* int current time in seconds; for pet age calculations
* pointer to active pet name string
* nested structure, with item count being subgame count
** byte subgame id (see above for id to game mapping)
** byte plays today
** byte max daily plays
** int seconds since score submission count resets
** int seconds at which score submission count resets
* nested structure, with item count being pet name count
** pointer to pet name string
* pointer to bank account title string
* pointer to bank account type string (same as title?)
* int bank balance
* int bank interest rate
* int max possible cumulative interest collectable before next sync
* bool has interest already been collected today
* nested structure, with item count being inventory item count
** pointer to unused string
** pointer to item name
** pointer to item category (user-visible)
** pointer to item type (not user-visible but seems to be the generic version of a category; for example, this would always be Petpet even if the type is Tyrannian Petpet)
** int unused
** int item ID (specific to Neopets Mobile; NOT the equivalent website item ID)
** int rarity
** int estimated value
** int weight
** bool unused
** bool can this item only be used online
** pointer to image location string
** nested structure, with item count being action count
*** byte action ID
*** pointer to action name string
* nested structure, with item count being neofriend count
** pointer to username string
** int flags (see above for meaning)
* '''nested structure, unknown'''
** '''byte unknown'''
** '''pointer to unknown string'''
* nested structure, unused
** int unused
* nested structure, with item count being talisman bead type 1 count
** int id
* nested structure, with item count being talisman bead type 2 count
** int id
* nested structure, with item count being talisman bead type 3 count
** int id
* nested structure, with item count being talisman bead type 4 count
** int id
* pointer to active pet switch string (as in "Berrysap the Rainbow Bori"?)
* pointer to unused string
* pointer to active pet species string
* pointer to unknown string
* pointer to active pet colour string
* pointer to unknown string
* pointer to active pet gender string
* int active pet level
* int active pet creation time in seconds
* int active pet current health
* int active pet max health
* int active pet happiness
* int active pet hunger
* int active pet strength
* int active pet defense
* int active pet movement
* int active pet intelligence
* int active pet illness cure item ID
* int unused
* int unused
* pointer to unused string
* pointer to active pet illness name string
* pointer to unused string
* pointer to active pet illness cure item name string
* pointer to unused string
* pointer to petpet name for loading purposes string (same as actual name?)
* pointer to petpet name string
* int petpet item ID
* int petpet level
* pointer to petpet image location string
* pointer to unused string
* pointer to petpetpet string
* int unused
* pointer to petpetpet image location string
* nested structure, unused
** int unused
* pointer to pet 1 image location string
* pointer to pet 2 image location string
* pointer to pet 3 image location string
* pointer to pet 4 image location string

=== Do nothing (40964, 40972) ===

These are no-operation responses, but the data still needs to be in a valid format.

Number buffer contents:
* pointer to encoding string

=== Rejected details (40966) ===

Number buffer contents:
* bool is username usable
* bool is username taken
* bool is password usable
* int unused
* nested structure, with item count being username suggestion count (up to 4)
** pointer to username suggestion string
* bool is pet name usable
* bool is pet name taken
* bool is pet name taken (again?)
* int unused
* nested structure, with item count being pet name suggestion count (up to 4)
** pointer to pet name suggestion string

=== Unlock information (40974) ===

The game only prints this to the console.

Number buffer contents:
* pointer to encoding string
* pointer to "short code" string
* int "nbSms"
* pointer to price string
* pointer to currency string

== See also ==

* [[Neopets Mobile strings]]


[[Category:Neopets]]
[[Category:Neopets]]

Latest revision as of 01:04, 2 June 2023

Neopets Mobile does not refer to the 2021 interface of the website, but the 2006 flip phone application that has long been discontinued.

Archival

https://www.jellyneo.net/?go=mobile

https://pinkpt.com//neodex/index.php?title=Neopets_Mobile

https://drive.google.com/file/d/1Cj8hqk4VI-O408kgMnKpffPmI-kxKmWR/view

Attempts to reverse engineer the long-defunct API

TODO (The jars are all minified, but perhaps I can extract the API URLs from them and document what the application expects to get back)

The META-INF/MANIFEST.MF for the Nokia 6280 version specifies a Java version of 1.4.2_04.

The decompiler used is quiltflower: https://github.com/QuiltMC/quiltflower and the javax.microedition classes were copied from https://github.com/mcpat/java-microedition-libraries

Nokia 6280 V02.30.00 (en) Singtel

m.java contains two calls:

The session check appears to return one of the following values, with anything else as a failure code of -1:

Response Treated as ID
SUBSCRIBED 1
UNSUBSCRIBED 2
REVOKED 3
SECURITY 5

Nokia 6111

m.java contains one call:

Getting sample network requests

  1. Install Kahvibreak
  2. Edit /path/to/Kahvibreak/Software/win32/KLaunch.bat
  3. Change echo NetworkNotAvailable=true>>property.txt to echo NetworkNotAvailable=false>>property.txt
  4. Edit /etc/hosts
  5. Add 127.0.0.1 npprod-singtel.in-fusio.com
  6. Add 127.0.0.1 npprod.in-fusio.com
  7. Run something on port 80 that listens to /data-np/
  8. Launch Neopets Mobile from Kahvibreak
  9. Try to login

Reverse engineering the format

I've been renaming symbols in the decompiled source code to slowly figure out what the application is looking for as a response.

The response seems to use the same data structure as the request: a form-encoded set of key-value pairs, then a newline, then some sort of binary data structure.

Numbers are big-endian. Strings are delayed until the end of the structure. However, a reference to a string may appear in the number buffer as a short representing the offset in the string buffer to the start of the string. The start of the string is a short representing the length of the string, followed by the text of the string itself. Note that the first item in the number buffer will always be a pointer to the encoding information string in the string buffer, which itself is the first item of the string buffer.

Nested structures can also be in the string buffer. They are handled similarly: the number buffer contains the offset to the start of the nested structure in the string buffer. However, the nested structure does not have its first six bytes, and the meaning of the "number buffer len + 2 (n)" field is changed to "number of items in this structure".

The game ID is hardcoded to 11061 and the center is hardcoded to 61.

After the form data and newline, the structured data looks like this:

Offset Type Meaning
0 short Tag
2 int Length-derived value: 8 * (2 + n + m)
6 short number buffer len + 2 (n)
8 bytes number buffer
n + 8 bytes string buffer
m byte 0xFF, end of structured data

For example, the login attempt above can be broken into the following parts:

{'client': 'NEOPETS/2.8', 'game': '11061', 'center': '61', 'language': 'en'}
Tag: 40961 (a001)
Number buffer: b'\x00\x00\x00\x00\x00@\x00\x00\x00@\x00\x10\x00\x18\x00 '
String buffer: b'\x00\x0eISO-8859-1;2.8\x00\x06adadad\x00\x06gjgjgj\x00\x00\x00'

Note that if tag == 0x8000 or 0x8064, a different format is followed:

Offset Type Meaning
0 short Tag
2 int (len(message) + 1) * 8
6 byte 0x00, start of message
7 string error message to display in console

The application emits the following request tags:

  • 33022 (test writing numbers)
  • 40961 (login)
  • 40963 (write state)
  • 40965 (login + ?)
  • 40967 (create pet + create account)
  • 40968 (create pet)
  • 40969 (add item)
  • 40971 (test writing strings)
  • 40973 (request unlock info)

The application handles the following response tags:

  • 40960 (sync status)
  • 40962 (user info)
  • 40964 (does nothing)
  • 40966 (rejected username, password, or pet name)
  • 40970 (info about added item)
  • 40972 (does nothing)
  • 40974 (unlock info)

Subgame IDs

Each subgame has a number of times it can be played (or score submitted) each day.

  • 21: Lutari Savings Bank
  • 22: Island Market
  • 23: Bog of Charity
  • 24: Wheel of Happiness
  • 25: Survival Academy
  • 26: Fluorescent Pools
  • 27: Blockstravaganza!
  • 28: Go Go Lutari!

NeoFriend flag IDs

Bit IDs start at 0, with the least significant bit being 0.

  • 8: Outgoing Neomail not synchronized?
  • 9: Accepted invitation since last check?
  • 10: Always set?
  • 11: Invitation already sent
  • 12: Registered for Neopets Mobile
  • 13: Neopets Mobile message pending?

Requests

Test writing numbers (33022)

Number buffer contains:

  • pointer to encoding string
  • constant int 0x0
  • boolean hardcoded to true

Logging in (40961, 40965)

With username "adadad" and password "gjgjgj", in Python 3 bytes notation:

b'client=NEOPETS/2.8&game=11061&center=61&language=en\n\xa0\x01\x00\x00\x01\xa0\x00\x12\x00\x00\x00\x00\x00@\x00\x00\x00@\x00\x10\x00\x18\x00 \x00\x0eISO-8859-1;2.8\x00\x06adadad\x00\x06gjgjgj\x00\x00\x00\xff'

Number buffer contents:

  • pointer to encoding string
  • constant int 0x64, doesn't mean anything
  • constant int 0x64, doesn't mean anything
  • pointer to username string
  • pointer to password string
  • pointer to extraneous information string; seemingly usually a zero-length string

I don't know how 40965 semantically differs from the first one.

Creating a pet and signing up (40967, 40968)

With username "adadad", password "gjgjgj", male green Kacheek, name "cccccc", birthday 1999-12-31, health 6, strength weak, defense very poor, movement slow, height 36 cms, weight 26 lbs, in Python 3 bytes notation:

b'client=NEOPETS/2.8&game=11061&center=61&language=en\n\xa0\x07\x00\x00\x04\xd0\x00:\x00\x00\x00\x00\x00@\x00\x00\x00@\x00\x10\x00\x18\x00 \x00(\x004\x00:\x00>\x00B\x00J\x00S\x00Z\x00\x00\x00\x06\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x05\x00\x00\x00$\x00\x00\x00\x1a\x00\x0eISO-8859-1;2.8\x00\x06adadad\x00\x06gjgjgj\x00\x06cccccc\x00\n1999-12-31\x00\x04Male\x00\x02en\x00\x02EN\x00\x06adadad\x00\x07Kacheek\x00\x05GREEN\x00\x04Male\x00\xff'

Number buffer contents:

  • pointer to encoding string
  • constant int 0x64, doesn't mean anything
  • constant int 0x64, doesn't mean anything
  • pointer to username string
  • pointer to password string
  • pointer to pet name
  • if 40967, pointer to date of birth string (YYYY-MM-DD)
  • if 40967, pointer to gender string (Male, Female)
  • if 40967, pointer to lowercase language string (en)
  • if 40967, pointer to uppercase language string (EN)
  • if 40967, pointer to username string again
  • pointer to species string (Kacheek, Kougra, Shoyru, Lutari)
  • pointer to colour string (GREEN, RED, YELLOW, BLUE)
  • pointer to gender string again
  • int pet health
  • int pet strength
  • int pet defense
  • int pet movement
  • int pet height
  • int pet weight

Add item to inventory (40969)

Number buffer contents:

  • pointer to encoding string
  • constant int 0x64, doesn't mean anything
  • constant int 0x64, doesn't mean anything
  • pointer to username string
  • pointer to password string
  • pointer to extraneous information string; seemingly usually a zero-length string
  • int mobile item ID, which does not appear to be the same as the website item ID

Test writing strings (40971)

Number buffer contents:

  • pointer to encoding string
  • pointer to an arbitrary string
  • pointer to "Check this out!"
  • pointer to "+33612345678"

Request unlock info (40973)

Number buffer contents:

  • pointer to encoding string

That's it.

Responses

Synchronization status (40960)

A break statement is missing after this in the application, but the next case throws an exception that is immediately swallowed, so everything is OK.

Number buffer contents:

  • pointer to encoding string
  • int with sync status ID

Known sync status IDs:

  • 41: Already running a mobile game session

User info (40962)

Number buffer contents:

  • pointer to encoding string
  • int unused
  • int unused
  • pointer to unused string
  • int user referral status; if >> 31 & 1 == 1, user maybe clicked a referral link?
  • int neopoints
  • pointer to Island Gossip string
  • int current time in seconds; for pet age calculations
  • pointer to active pet name string
  • nested structure, with item count being subgame count
    • byte subgame id (see above for id to game mapping)
    • byte plays today
    • byte max daily plays
    • int seconds since score submission count resets
    • int seconds at which score submission count resets
  • nested structure, with item count being pet name count
    • pointer to pet name string
  • pointer to bank account title string
  • pointer to bank account type string (same as title?)
  • int bank balance
  • int bank interest rate
  • int max possible cumulative interest collectable before next sync
  • bool has interest already been collected today
  • nested structure, with item count being inventory item count
    • pointer to unused string
    • pointer to item name
    • pointer to item category (user-visible)
    • pointer to item type (not user-visible but seems to be the generic version of a category; for example, this would always be Petpet even if the type is Tyrannian Petpet)
    • int unused
    • int item ID (specific to Neopets Mobile; NOT the equivalent website item ID)
    • int rarity
    • int estimated value
    • int weight
    • bool unused
    • bool can this item only be used online
    • pointer to image location string
    • nested structure, with item count being action count
      • byte action ID
      • pointer to action name string
  • nested structure, with item count being neofriend count
    • pointer to username string
    • int flags (see above for meaning)
  • nested structure, unknown
    • byte unknown
    • pointer to unknown string
  • nested structure, unused
    • int unused
  • nested structure, with item count being talisman bead type 1 count
    • int id
  • nested structure, with item count being talisman bead type 2 count
    • int id
  • nested structure, with item count being talisman bead type 3 count
    • int id
  • nested structure, with item count being talisman bead type 4 count
    • int id
  • pointer to active pet switch string (as in "Berrysap the Rainbow Bori"?)
  • pointer to unused string
  • pointer to active pet species string
  • pointer to unknown string
  • pointer to active pet colour string
  • pointer to unknown string
  • pointer to active pet gender string
  • int active pet level
  • int active pet creation time in seconds
  • int active pet current health
  • int active pet max health
  • int active pet happiness
  • int active pet hunger
  • int active pet strength
  • int active pet defense
  • int active pet movement
  • int active pet intelligence
  • int active pet illness cure item ID
  • int unused
  • int unused
  • pointer to unused string
  • pointer to active pet illness name string
  • pointer to unused string
  • pointer to active pet illness cure item name string
  • pointer to unused string
  • pointer to petpet name for loading purposes string (same as actual name?)
  • pointer to petpet name string
  • int petpet item ID
  • int petpet level
  • pointer to petpet image location string
  • pointer to unused string
  • pointer to petpetpet string
  • int unused
  • pointer to petpetpet image location string
  • nested structure, unused
    • int unused
  • pointer to pet 1 image location string
  • pointer to pet 2 image location string
  • pointer to pet 3 image location string
  • pointer to pet 4 image location string

Do nothing (40964, 40972)

These are no-operation responses, but the data still needs to be in a valid format.

Number buffer contents:

  • pointer to encoding string

Rejected details (40966)

Number buffer contents:

  • bool is username usable
  • bool is username taken
  • bool is password usable
  • int unused
  • nested structure, with item count being username suggestion count (up to 4)
    • pointer to username suggestion string
  • bool is pet name usable
  • bool is pet name taken
  • bool is pet name taken (again?)
  • int unused
  • nested structure, with item count being pet name suggestion count (up to 4)
    • pointer to pet name suggestion string

Unlock information (40974)

The game only prints this to the console.

Number buffer contents:

  • pointer to encoding string
  • pointer to "short code" string
  • int "nbSms"
  • pointer to price string
  • pointer to currency string

See also