Barebones PRUDP/NEX server library written in Go
Find a file
2018-10-03 19:33:14 -05:00
.gitignore restructure and, rewrite. Things do things now 2018-09-18 00:25:31 -04:00
client.go Some small code clean up 2018-10-02 17:18:54 -04:00
common.go update documentation on the checksum calculator and the signature calculator of v0 packets 2018-10-02 23:05:06 -05:00
compression.go Properly send fragmented packets + godoc comments 2018-09-26 21:42:48 -04:00
kerberos.go Minor updates 2018-09-25 10:10:20 -04:00
nex_stream.go Added GoDoc comments on exported values 2018-10-02 17:10:59 -04:00
packet.go finish editing 'packet_v1.go' and add documentation for some helper methods and functions of the 'packet.go' file 2018-10-03 19:33:14 -05:00
packet_v0.go update documentation on the checksum calculator and the signature calculator of v0 packets 2018-10-02 23:05:06 -05:00
packet_v1.go finish editing 'packet_v1.go' and add documentation for some helper methods and functions of the 'packet.go' file 2018-10-03 19:33:14 -05:00
README.md Updated README to have a basic example 2018-10-02 17:28:10 -04:00
rmc.go Minor updates 2018-09-25 10:10:20 -04:00
server.go Basic v1 implementation (still kinda broken) 2018-10-02 17:02:36 -04:00
types.go Properly send fragmented packets + godoc comments 2018-09-26 21:42:48 -04:00

NEX related libraries to make NEX servers in Go

GoDoc

How to install and use

Install

go get https://github.com/PretendoNetwork/nex-go

Usage

package main

import (
	"fmt"

	NEX "https://github.com/PretendoNetwork/nex-go"
)

// Bare-bones example of the structure of the Friends service AUTH server for the WiiU/3DS

/*
	THIS IS VERY ROUGH EXAMPLE, USING TECHNIQUES THAT SHOULD NOT BE USED
	NO REAL AUTHENTICATION OR CHECKS ARE GOING ON, THIS EXAMPLE JUST
	BRUTE-FORCES THE USER THROUGH AUTHENTICATION.
*/

func main() {

	settings := NEX.NewSettings()

	settings.PrudpVersion = 0
	settings.PrudpV0SignatureVersion = 1
	settings.KerberosKeySize = 16
	settings.AccessKey = "ridfebb9"

	fmt.Println("STARTING FRIENDS AUTH SERVER")

	Server := NEX.NewServer(settings)

	Server.On("Packet", func(Client *NEX.Client, Packet *NEX.Packet) {
		// Acknowledge every packet if it needs it. If it makes it this far, it's good
		if Packet.HasFlag(NEX.Flags["NeedAck"]) {
			Server.Acknowledge(Packet)
		}
	})

	Server.On("Data", func(Client *NEX.Client, Packet *NEX.Packet) {
		stream := NEX.NewInputStream(Packet.RMCRequest.Parameters)
		response := NEX.NewRMCResponse(0x0A, Packet.RMCRequest.Header.CallID)
		responseStream := NEX.NewOutputStream()

		ResponsePacket := NEX.NewPacket(Client)

		ResponsePacket.SetVersion(0)
		ResponsePacket.SetSource(Packet.Destination)
		ResponsePacket.SetDestination(Packet.Source)
		ResponsePacket.SetType(NEX.Types["Data"])

		pid := 1234567890          // account PID/NEX username (dummy)
		password := "nex_password" // account NEX password (dummy)

		key := []byte(password)

		for i := 0; i < 65000+pid%1024; i++ {
			key = NEX.MD5Hash(key)
		}

		Kerberos := NEX.NewKerberos(string(key))

		// Checking the Method ID in this way is generally bad.
		// A better way would be to track each protocol and have a reference to it's methods stored by their ID,
		// and dynamically getting the handler
		if Packet.RMCRequest.Header.MethodID == 2 { // 0x0A::0x02 (LoginEx)
			_ = stream.String()     // username
			_ = stream.DataHolder() // login data

			Kerberos := NEX.NewKerberos(string(key))
			str := "test string test" // dummy data

			kerberosData := Kerberos.Encrypt([]byte(str))

			JSONBuffer := []byte(`{
				"stream":  "10",
				"type": "2",
				"PID": "2",
				"port": "60001",
				"address": "127.0.0.1",
				"sid": "1",
				"CID": "1"
			}`)

			var JSON map[string]string
			_ = json.Unmarshal(JSONBuffer, &JSON)

			station := NEX.NewStationURL("prudps", JSON)

			name := "branch:origin/feature/45925_FixAutoReconnect build:3_10_11_2006_0" // official server

			responseStream.UInt32LE(uint32(0x00010001)) // success
			responseStream.UInt32LE(uint32(pid))
			responseStream.Buffer(kerberosData)

			responseStream.String(station)     // Station URL (normal)
			responseStream.UInt32LE(uint32(0)) // Special protocols (unused)
			responseStream.String("")          // Station URL (special) (unused)

			responseStream.String(name)

			response.SetSuccess(uint32(2), responseStream.Bytes())

			ResponsePacket.SetPayload(response.Bytes())
		} else if Packet.RMCRequest.Header.MethodID == 3 {  // 0x0A::0x03 (RequestTicket)
			str := "test string test test string tes" // dummy data

			_ = stream.UInt32LE() // User PID
			_ = stream.UInt32LE() // Server PID?

			responseStream.UInt32LE(uint32(0x00010001)) // success

			kerberosStream := NEX.NewOutputStream()

			kerberosStream.Write([]byte("I like chickens.")) // Kerberos key (dummy)
			kerberosStream.UInt32LE(uint32(0xFFFFFFFF))      // Unknown PID
			kerberosStream.Buffer([]byte(str))               // Kerberos data

			kerberosData := Kerberos.Encrypt(kerberosStream.Bytes())

			responseStream.Buffer(kerberosData)

			response.SetSuccess(uint32(3), responseStream.Bytes())

		} else {
			panic("INVALID PROTOCOL METHOD ID " + string(Packet.RMCRequest.Header.MethodID))
		}

		ResponsePacket.SetPayload(response.Bytes())
		Server.Send(Client, &ResponsePacket)
	})

	Server.Listen(":60000")
}