diff --git a/common/token/token.go b/common/token/token.go
new file mode 100644
index 000000000..73568bcbc
--- /dev/null
+++ b/common/token/token.go
@@ -0,0 +1,13 @@
+package token
+
+import "math/rand"
+
+// Generate returns an alphanumeric token of specified length
+func Generate(length int) string {
+ var chars = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789")
+ b := make([]rune, length)
+ for i := range b {
+ b[i] = chars[rand.Intn(len(chars))]
+ }
+ return string(b)
+}
diff --git a/config.json b/config.json
index 5e23789d8..fcf7d3c0f 100644
--- a/config.json
+++ b/config.json
@@ -3,13 +3,14 @@
"BinPath": "bin",
"DisableSoftCrash": false,
"FeaturedWeapons": 1,
+ "HideLoginNotice": true,
+ "LoginNotice": "
Welcome to Erupe SU9.1!
Erupe is experimental software, we are not liable for any
issues caused by installing the software!
■Report bugs on Discord!
■Test everything!
■Don't talk to softlocking NPCs!
■Fork the code on GitHub!
Thank you to all of the contributors,
this wouldn't exist without you.",
+ "PatchServerManifest": "",
+ "PatchServerFile": "",
+ "ScreenshotAPIURL": "",
"DevMode": true,
"DevModeOptions": {
- "PatchServerManifest": "",
- "PatchServerFile": "",
"AutoCreateAccount": true,
- "HideLoginNotice": false,
- "LoginNotice": "Welcome to Erupe SU9.1!
Erupe is experimental software, we are not liable for any
issues caused by installing the software!
■Report bugs on Discord!
■Test everything!
■Don't talk to softlocking NPCs!
■Fork the code on GitHub!
Thank you to all of the contributors,
this wouldn't exist without you.",
"CleanDB": false,
"MaxLauncherHR": false,
"LogInboundMessages": false,
diff --git a/config/config.go b/config/config.go
index 8fde5293a..9c9b6b7db 100644
--- a/config/config.go
+++ b/config/config.go
@@ -12,11 +12,16 @@ import (
// Config holds the global server-wide config.
type Config struct {
- Host string `mapstructure:"Host"`
- BinPath string `mapstructure:"BinPath"`
- DisableSoftCrash bool // Disables the 'Press Return to exit' dialog allowing scripts to reboot the server automatically
- FeaturedWeapons int // Number of Active Feature weapons to generate daily
- DevMode bool
+ Host string `mapstructure:"Host"`
+ BinPath string `mapstructure:"BinPath"`
+ DisableSoftCrash bool // Disables the 'Press Return to exit' dialog allowing scripts to reboot the server automatically
+ FeaturedWeapons int // Number of Active Feature weapons to generate daily
+ HideLoginNotice bool // Hide the Erupe notice on login
+ LoginNotice string // MHFML string of the login notice displayed
+ PatchServerManifest string // Manifest patch server override
+ PatchServerFile string // File patch server override
+ ScreenshotAPIURL string // Destination for screenshots uploaded to BBS
+ DevMode bool
DevModeOptions DevModeOptions
Discord Discord
@@ -32,24 +37,20 @@ type Config struct {
// DevModeOptions holds various debug/temporary options for use while developing Erupe.
type DevModeOptions struct {
- PatchServerManifest string // Manifest patch server override
- PatchServerFile string // File patch server override
- AutoCreateAccount bool // Automatically create accounts if they don't exist
- HideLoginNotice bool // Hide the Erupe notice on login
- LoginNotice string // MHFML string of the login notice displayed
- CleanDB bool // Automatically wipes the DB on server reset.
- MaxLauncherHR bool // Sets the HR returned in the launcher to HR7 so that you can join non-beginner worlds.
- LogInboundMessages bool // Log all messages sent to the server
- LogOutboundMessages bool // Log all messages sent to the clients
- MaxHexdumpLength int // Maximum number of bytes printed when logs are enabled
- DivaEvent int // Diva Defense event status
- FestaEvent int // Hunter's Festa event status
- TournamentEvent int // VS Tournament event status
- MezFesEvent bool // MezFes status
- MezFesAlt bool // Swaps out Volpakkun for Tokotoko
- DisableTokenCheck bool // Disables checking login token exists in the DB (security risk!)
- DisableMailItems bool // Hack to prevent english versions of MHF from crashing
- QuestDebugTools bool // Enable various quest debug logs
+ AutoCreateAccount bool // Automatically create accounts if they don't exist
+ CleanDB bool // Automatically wipes the DB on server reset.
+ MaxLauncherHR bool // Sets the HR returned in the launcher to HR7 so that you can join non-beginner worlds.
+ LogInboundMessages bool // Log all messages sent to the server
+ LogOutboundMessages bool // Log all messages sent to the clients
+ MaxHexdumpLength int // Maximum number of bytes printed when logs are enabled
+ DivaEvent int // Diva Defense event status
+ FestaEvent int // Hunter's Festa event status
+ TournamentEvent int // VS Tournament event status
+ MezFesEvent bool // MezFes status
+ MezFesAlt bool // Swaps out Volpakkun for Tokotoko
+ DisableTokenCheck bool // Disables checking login token exists in the DB (security risk!)
+ DisableMailItems bool // Hack to prevent english versions of MHF from crashing
+ QuestDebugTools bool // Enable various quest debug logs
SaveDumps SaveDumpOptions
}
diff --git a/network/mhfpacket/msg_mhf_apply_bbs_article.go b/network/mhfpacket/msg_mhf_apply_bbs_article.go
index df0218ce0..d2b9c803b 100644
--- a/network/mhfpacket/msg_mhf_apply_bbs_article.go
+++ b/network/mhfpacket/msg_mhf_apply_bbs_article.go
@@ -1,15 +1,24 @@
package mhfpacket
-import (
- "errors"
+import (
+ "errors"
+ "erupe-ce/common/bfutil"
+ "erupe-ce/common/stringsupport"
- "erupe-ce/network/clientctx"
- "erupe-ce/network"
"erupe-ce/common/byteframe"
+ "erupe-ce/network"
+ "erupe-ce/network/clientctx"
)
// MsgMhfApplyBbsArticle represents the MSG_MHF_APPLY_BBS_ARTICLE
-type MsgMhfApplyBbsArticle struct{}
+type MsgMhfApplyBbsArticle struct {
+ AckHandle uint32
+ Unk0 uint32
+ Unk1 []byte
+ Name string
+ Title string
+ Description string
+}
// Opcode returns the ID associated with this packet type.
func (m *MsgMhfApplyBbsArticle) Opcode() network.PacketID {
@@ -18,7 +27,13 @@ func (m *MsgMhfApplyBbsArticle) Opcode() network.PacketID {
// Parse parses the packet from binary
func (m *MsgMhfApplyBbsArticle) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
- return errors.New("NOT IMPLEMENTED")
+ m.AckHandle = bf.ReadUint32()
+ m.Unk0 = bf.ReadUint32()
+ m.Unk1 = bf.ReadBytes(16)
+ m.Name = stringsupport.SJISToUTF8(bfutil.UpToNull(bf.ReadBytes(32)))
+ m.Title = stringsupport.SJISToUTF8(bfutil.UpToNull(bf.ReadBytes(128)))
+ m.Description = stringsupport.SJISToUTF8(bfutil.UpToNull(bf.ReadBytes(256)))
+ return nil
}
// Build builds a binary packet from the current data.
diff --git a/network/mhfpacket/msg_mhf_get_bbs_sns_status.go b/network/mhfpacket/msg_mhf_get_bbs_sns_status.go
index 07ab9e485..0c50f67e8 100644
--- a/network/mhfpacket/msg_mhf_get_bbs_sns_status.go
+++ b/network/mhfpacket/msg_mhf_get_bbs_sns_status.go
@@ -1,15 +1,18 @@
package mhfpacket
-import (
- "errors"
+import (
+ "errors"
- "erupe-ce/network/clientctx"
- "erupe-ce/network"
"erupe-ce/common/byteframe"
+ "erupe-ce/network"
+ "erupe-ce/network/clientctx"
)
// MsgMhfGetBbsSnsStatus represents the MSG_MHF_GET_BBS_SNS_STATUS
-type MsgMhfGetBbsSnsStatus struct{}
+type MsgMhfGetBbsSnsStatus struct {
+ AckHandle uint32
+ Unk []byte
+}
// Opcode returns the ID associated with this packet type.
func (m *MsgMhfGetBbsSnsStatus) Opcode() network.PacketID {
@@ -18,7 +21,9 @@ func (m *MsgMhfGetBbsSnsStatus) Opcode() network.PacketID {
// Parse parses the packet from binary
func (m *MsgMhfGetBbsSnsStatus) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
- return errors.New("NOT IMPLEMENTED")
+ m.AckHandle = bf.ReadUint32()
+ m.Unk = bf.ReadBytes(12)
+ return nil
}
// Build builds a binary packet from the current data.
diff --git a/network/mhfpacket/msg_mhf_get_bbs_user_status.go b/network/mhfpacket/msg_mhf_get_bbs_user_status.go
index 69bcef671..9c44faa76 100644
--- a/network/mhfpacket/msg_mhf_get_bbs_user_status.go
+++ b/network/mhfpacket/msg_mhf_get_bbs_user_status.go
@@ -1,15 +1,18 @@
package mhfpacket
-import (
- "errors"
+import (
+ "errors"
- "erupe-ce/network/clientctx"
- "erupe-ce/network"
"erupe-ce/common/byteframe"
+ "erupe-ce/network"
+ "erupe-ce/network/clientctx"
)
// MsgMhfGetBbsUserStatus represents the MSG_MHF_GET_BBS_USER_STATUS
-type MsgMhfGetBbsUserStatus struct{}
+type MsgMhfGetBbsUserStatus struct {
+ AckHandle uint32
+ Unk []byte
+}
// Opcode returns the ID associated with this packet type.
func (m *MsgMhfGetBbsUserStatus) Opcode() network.PacketID {
@@ -18,7 +21,9 @@ func (m *MsgMhfGetBbsUserStatus) Opcode() network.PacketID {
// Parse parses the packet from binary
func (m *MsgMhfGetBbsUserStatus) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
- return errors.New("NOT IMPLEMENTED")
+ m.AckHandle = bf.ReadUint32()
+ m.Unk = bf.ReadBytes(12)
+ return nil
}
// Build builds a binary packet from the current data.
diff --git a/server/channelserver/handlers.go b/server/channelserver/handlers.go
index 47d3d6b4c..b1af93beb 100644
--- a/server/channelserver/handlers.go
+++ b/server/channelserver/handlers.go
@@ -1495,10 +1495,6 @@ func handleMsgMhfInfoScenarioCounter(s *Session, p mhfpacket.MHFPacket) {
doAckBufSucceed(s, pkt.AckHandle, resp.Data())
}
-func handleMsgMhfGetBbsSnsStatus(s *Session, p mhfpacket.MHFPacket) {}
-
-func handleMsgMhfApplyBbsArticle(s *Session, p mhfpacket.MHFPacket) {}
-
func handleMsgMhfGetEtcPoints(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfGetEtcPoints)
diff --git a/server/channelserver/handlers_bbs.go b/server/channelserver/handlers_bbs.go
new file mode 100644
index 000000000..222a8eadc
--- /dev/null
+++ b/server/channelserver/handlers_bbs.go
@@ -0,0 +1,41 @@
+package channelserver
+
+import (
+ "erupe-ce/common/byteframe"
+ "erupe-ce/common/stringsupport"
+ "erupe-ce/common/token"
+ "erupe-ce/network/mhfpacket"
+)
+
+func handleMsgMhfGetBbsUserStatus(s *Session, p mhfpacket.MHFPacket) {
+ pkt := p.(*mhfpacket.MsgMhfGetBbsUserStatus)
+ bf := byteframe.NewByteFrame()
+ bf.WriteUint32(200)
+ bf.WriteUint32(0)
+ bf.WriteUint32(0)
+ bf.WriteUint32(0)
+ doAckBufSucceed(s, pkt.AckHandle, bf.Data())
+}
+
+func handleMsgMhfGetBbsSnsStatus(s *Session, p mhfpacket.MHFPacket) {
+ pkt := p.(*mhfpacket.MsgMhfGetBbsSnsStatus)
+ bf := byteframe.NewByteFrame()
+ bf.WriteUint32(200)
+ bf.WriteUint32(401)
+ bf.WriteUint32(401)
+ bf.WriteUint32(0)
+ doAckBufSucceed(s, pkt.AckHandle, bf.Data())
+}
+
+func handleMsgMhfApplyBbsArticle(s *Session, p mhfpacket.MHFPacket) {
+ pkt := p.(*mhfpacket.MsgMhfApplyBbsArticle)
+ bf := byteframe.NewByteFrame()
+ articleToken := token.Generate(40)
+ bf.WriteUint32(200)
+ bf.WriteUint32(80)
+ bf.WriteUint32(0)
+ bf.WriteUint32(0)
+ bf.WriteBytes(stringsupport.PaddedString(articleToken, 64, false))
+ bf.WriteBytes(stringsupport.PaddedString(s.server.erupeConfig.ScreenshotAPIURL, 64, false))
+ doAckBufSucceed(s, pkt.AckHandle, bf.Data())
+}
diff --git a/server/channelserver/handlers_users.go b/server/channelserver/handlers_users.go
index c360b82a6..fc8b47a8d 100644
--- a/server/channelserver/handlers_users.go
+++ b/server/channelserver/handlers_users.go
@@ -54,5 +54,3 @@ func handleMsgSysGetUserBinary(s *Session, p mhfpacket.MHFPacket) {
}
func handleMsgSysNotifyUserBinary(s *Session, p mhfpacket.MHFPacket) {}
-
-func handleMsgMhfGetBbsUserStatus(s *Session, p mhfpacket.MHFPacket) {}
diff --git a/server/signserver/dsgn_resp.go b/server/signserver/dsgn_resp.go
index 3966af8d6..9335de0c0 100644
--- a/server/signserver/dsgn_resp.go
+++ b/server/signserver/dsgn_resp.go
@@ -4,6 +4,7 @@ import (
"erupe-ce/common/byteframe"
ps "erupe-ce/common/pascalstring"
"erupe-ce/common/stringsupport"
+ "erupe-ce/common/token"
"erupe-ce/server/channelserver"
"fmt"
"math/rand"
@@ -18,15 +19,6 @@ func makeSignInFailureResp(respID RespID) []byte {
return bf.Data()
}
-func randSeq(n int) string {
- var letters = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
- b := make([]rune, n)
- for i := range b {
- b[i] = letters[rand.Intn(len(letters))]
- }
- return string(b)
-}
-
func (s *Session) makeSignInResp(uid int) []byte {
returnExpiry := s.server.getReturnExpiry(uid)
@@ -37,13 +29,13 @@ func (s *Session) makeSignInResp(uid int) []byte {
}
rand.Seed(time.Now().UnixNano())
- token := randSeq(16)
- s.server.registerToken(uid, token)
+ sessToken := token.Generate(16)
+ s.server.registerToken(uid, sessToken)
bf := byteframe.NewByteFrame()
bf.WriteUint8(1) // resp_code
- if s.server.erupeConfig.DevMode && s.server.erupeConfig.DevModeOptions.PatchServerManifest != "" && s.server.erupeConfig.DevModeOptions.PatchServerFile != "" {
+ if s.server.erupeConfig.DevMode && s.server.erupeConfig.PatchServerManifest != "" && s.server.erupeConfig.PatchServerFile != "" {
bf.WriteUint8(2)
} else {
bf.WriteUint8(0)
@@ -51,12 +43,12 @@ func (s *Session) makeSignInResp(uid int) []byte {
bf.WriteUint8(1) // entrance server count
bf.WriteUint8(uint8(len(chars))) // character count
bf.WriteUint32(0xFFFFFFFF) // login_token_number
- bf.WriteBytes([]byte(token)) // login_token
+ bf.WriteBytes([]byte(sessToken)) // login_token
bf.WriteUint32(uint32(time.Now().Unix())) // current time
if s.server.erupeConfig.DevMode {
- if s.server.erupeConfig.DevModeOptions.PatchServerManifest != "" && s.server.erupeConfig.DevModeOptions.PatchServerFile != "" {
- ps.Uint8(bf, s.server.erupeConfig.DevModeOptions.PatchServerManifest, false)
- ps.Uint8(bf, s.server.erupeConfig.DevModeOptions.PatchServerFile, false)
+ if s.server.erupeConfig.PatchServerManifest != "" && s.server.erupeConfig.PatchServerFile != "" {
+ ps.Uint8(bf, s.server.erupeConfig.PatchServerManifest, false)
+ ps.Uint8(bf, s.server.erupeConfig.PatchServerFile, false)
}
}
ps.Uint8(bf, fmt.Sprintf("%s:%d", s.server.erupeConfig.Host, s.server.erupeConfig.Entrance.Port), false)
@@ -111,11 +103,11 @@ func (s *Session) makeSignInResp(uid int) []byte {
}
}
- if s.server.erupeConfig.DevModeOptions.HideLoginNotice {
+ if s.server.erupeConfig.HideLoginNotice {
bf.WriteUint8(0)
} else {
bf.WriteUint8(1) // Notice count
- noticeText := s.server.erupeConfig.DevModeOptions.LoginNotice
+ noticeText := s.server.erupeConfig.LoginNotice
ps.Uint32(bf, noticeText, true)
}