parent
92a9180ed2
commit
1de6f6e367
6 changed files with 103 additions and 2 deletions
10
PROTOCOL.md
10
PROTOCOL.md
|
@ -140,6 +140,16 @@ must write some data to the server at least once every 40 seconds.
|
|||
- Send a message to all players.
|
||||
- This command is only available to server administrators.
|
||||
|
||||
- `defcon [level]`
|
||||
- Apply restrictions to guests to prevent abuse.
|
||||
- This command is only available to server administrators and moderators.
|
||||
- Levels:
|
||||
1. Disallow new accounts from being registered.
|
||||
2. Only registered users may create and join matches.
|
||||
3. Only registered users may chat and set custom match titles.
|
||||
4. Warning message is broadcast to all users.
|
||||
5. Normal operation.
|
||||
|
||||
- `shutdown <minutes> <reason>`
|
||||
- Prevent the creation of new matches and periodically warn players about the server shutting down.
|
||||
- This command is only available to server administrators.
|
||||
|
|
|
@ -33,6 +33,7 @@ const (
|
|||
CommandDisconnect = "disconnect" // Disconnect from server.
|
||||
CommandMOTD = "motd" // Read (or write) the message of the day.
|
||||
CommandBroadcast = "broadcast" // Send a message to all players.
|
||||
CommandDefcon = "defcon" // Apply restrictions to guests to prevent abuse.
|
||||
CommandShutdown = "shutdown" // Prevent the creation of new matches.
|
||||
)
|
||||
|
||||
|
@ -82,12 +83,13 @@ var HelpText = map[string]string{
|
|||
CommandReset: "- Reset pending checker movement.",
|
||||
CommandOk: "[1-6] - Accept double offer or confirm checker movement. The parameter for this command only applies in acey-deucey games.",
|
||||
CommandRematch: "- Request (or accept) a rematch after a match has been finished.",
|
||||
CommandFollow: "- Follow a player. A notification is shown whenever a followed player goes online or offline.",
|
||||
CommandUnfollow: "- Un-follow a player.",
|
||||
CommandFollow: "<username> - Follow a player. A notification is shown whenever a followed player goes online or offline.",
|
||||
CommandUnfollow: "<username> - Un-follow a player.",
|
||||
CommandBoard: "- Request current match state.",
|
||||
CommandPong: "<message> - Sent in response to server ping event to prevent the connection from timing out.",
|
||||
CommandDisconnect: "- Disconnect from the server.",
|
||||
CommandMOTD: "[message] - View (or set) message of the day. Specifying a new message of the day is only available to server administrators.",
|
||||
CommandBroadcast: "<message> - Send a message to all players. This command is only available to server administrators.",
|
||||
CommandDefcon: "[level] - Apply restrictions to guests to prevent abuse. Levels:\n1. Disallow new accounts from being registered.\n2. Only registered users may create and join matches.\n3. Only registered users may chat and set custom match titles.\n4. Warning message is broadcast to all users.\n5. Normal operation.",
|
||||
CommandShutdown: "<minutes> <reason> - Prevent the creation of new matches and periodically warn players about the server shutting down. This command is only available to server administrators.",
|
||||
}
|
||||
|
|
|
@ -89,6 +89,10 @@ func (c *serverClient) Admin() bool {
|
|||
return c.accountID == 1
|
||||
}
|
||||
|
||||
func (c *serverClient) Mod() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (c *serverClient) sendEvent(e interface{}) {
|
||||
// JSON formatted messages.
|
||||
if c.json {
|
||||
|
@ -210,6 +214,20 @@ func (c *serverClient) sendBroadcast(message string) {
|
|||
})
|
||||
}
|
||||
|
||||
func (c *serverClient) sendDefconWarning(defcon int) {
|
||||
var message string
|
||||
if defcon == 4 {
|
||||
message = gotext.GetD(c.language, "Due to ongoing abuse, some actions may become restricted to registered users only. Please log in or register to avoid interruptions.")
|
||||
} else if defcon < 4 {
|
||||
message = gotext.GetD(c.language, "Due to ongoing abuse, some actions are restricted to registered users only. Please log in or register to avoid interruptions.")
|
||||
} else {
|
||||
return
|
||||
}
|
||||
c.sendEvent(&bgammon.EventNotice{
|
||||
Message: gotext.GetD(c.language, "SERVER BROADCAST:") + " " + message,
|
||||
})
|
||||
}
|
||||
|
||||
func (c *serverClient) label() string {
|
||||
if len(c.name) > 0 {
|
||||
return string(c.name)
|
||||
|
|
|
@ -49,6 +49,15 @@ msgstr ""
|
|||
msgid "Double offered to opponent (%d points)."
|
||||
msgstr ""
|
||||
|
||||
msgid "Due to ongoing abuse, registration is disabled. Please try again later."
|
||||
msgstr ""
|
||||
|
||||
msgid "Due to ongoing abuse, some actions are restricted to registered users only. Please log in or register to avoid interruptions."
|
||||
msgstr ""
|
||||
|
||||
msgid "Due to ongoing abuse, some actions may become restricted to registered users only. Please log in or register to avoid interruptions."
|
||||
msgstr ""
|
||||
|
||||
msgid "Failed to change password."
|
||||
msgstr ""
|
||||
|
||||
|
|
|
@ -78,6 +78,8 @@ type server struct {
|
|||
leaderboardCacheTime [12]time.Time
|
||||
leaderboardCacheLock sync.Mutex
|
||||
|
||||
defcon int
|
||||
|
||||
motd string
|
||||
|
||||
sortedCommands []string
|
||||
|
@ -104,6 +106,7 @@ func NewServer(tz string, dataSource string, mailServer string, passwordSalt str
|
|||
newClientIDs: make(chan int),
|
||||
commands: make(chan serverCommand, bufferSize),
|
||||
welcome: []byte("hello Welcome to bgammon.org! Please log in by sending the 'login' command. You may specify a username, otherwise you will be assigned a random username. If you specify a username, you may also specify a password. Have fun!"),
|
||||
defcon: 5,
|
||||
mailServer: mailServer,
|
||||
passwordSalt: passwordSalt,
|
||||
resetSalt: resetSalt,
|
||||
|
|
|
@ -38,6 +38,11 @@ func (s *server) handleFirstCommand(cmd serverCommand, keyword string, params []
|
|||
cmd.client.Terminate(gotext.GetD(cmd.client.language, "Please enter an email, username and password."))
|
||||
}
|
||||
|
||||
if s.defcon == 1 {
|
||||
cmd.client.Terminate(gotext.GetD(cmd.client.language, "Due to ongoing abuse, registration is disabled. Please try again later."))
|
||||
return
|
||||
}
|
||||
|
||||
var email []byte
|
||||
if keyword == bgammon.CommandRegisterJSON || keyword == "rj" {
|
||||
if len(params) < 4 {
|
||||
|
@ -221,6 +226,11 @@ func (s *server) handleFirstCommand(cmd serverCommand, keyword string, params []
|
|||
}
|
||||
}
|
||||
|
||||
// Send DEFCON warning message.
|
||||
if s.defcon != 5 {
|
||||
cmd.client.sendDefconWarning(s.defcon)
|
||||
}
|
||||
|
||||
// Send followed player notifications.
|
||||
c := cmd.client
|
||||
if c.accountID != 0 {
|
||||
|
@ -384,6 +394,10 @@ COMMANDS:
|
|||
cmd.client.sendNotice(gotext.GetD(cmd.client.language, "Message not sent: There is no one else in the match."))
|
||||
continue
|
||||
}
|
||||
if s.defcon < 4 && cmd.client.accountID == 0 {
|
||||
cmd.client.sendNotice(gotext.GetD(cmd.client.language, "Due to ongoing abuse, some actions are restricted to registered users only. Please log in or register to avoid interruptions."))
|
||||
continue
|
||||
}
|
||||
ev := &bgammon.EventSay{
|
||||
Message: string(bytes.Join(params, []byte(" "))),
|
||||
}
|
||||
|
@ -413,6 +427,11 @@ COMMANDS:
|
|||
continue
|
||||
}
|
||||
|
||||
if s.defcon < 3 && cmd.client.accountID == 0 {
|
||||
cmd.client.sendNotice(gotext.GetD(cmd.client.language, "Due to ongoing abuse, some actions are restricted to registered users only. Please log in or register to avoid interruptions."))
|
||||
continue
|
||||
}
|
||||
|
||||
var gamePassword []byte
|
||||
gameType := bytes.ToLower(params[0])
|
||||
var gameName []byte
|
||||
|
@ -465,6 +484,10 @@ COMMANDS:
|
|||
points = 127
|
||||
}
|
||||
|
||||
if s.defcon < 4 && cmd.client.accountID == 0 {
|
||||
gameName = nil
|
||||
}
|
||||
|
||||
// Set default game name.
|
||||
if len(bytes.TrimSpace(gameName)) == 0 {
|
||||
abbr := "'s"
|
||||
|
@ -507,6 +530,13 @@ COMMANDS:
|
|||
continue
|
||||
}
|
||||
|
||||
if s.defcon < 3 && cmd.client.accountID == 0 {
|
||||
cmd.client.sendEvent(&bgammon.EventFailedJoin{
|
||||
Reason: gotext.GetD(cmd.client.language, "Due to ongoing abuse, some actions are restricted to registered users only. Please log in or register to avoid interruptions."),
|
||||
})
|
||||
continue
|
||||
}
|
||||
|
||||
var joinGameID int
|
||||
if onlyNumbers.Match(params[0]) {
|
||||
gameID, err := strconv.Atoi(string(params[0]))
|
||||
|
@ -1411,6 +1441,35 @@ COMMANDS:
|
|||
sc.sendBroadcast(message)
|
||||
}
|
||||
s.clientsLock.Unlock()
|
||||
case bgammon.CommandDefcon:
|
||||
if len(params) == 0 {
|
||||
cmd.client.sendNotice(fmt.Sprintf("Current DEFCON level: %d.", s.defcon))
|
||||
continue
|
||||
} else if !cmd.client.Admin() && !cmd.client.Mod() {
|
||||
cmd.client.sendNotice("Access denied.")
|
||||
continue
|
||||
}
|
||||
|
||||
v, err := strconv.Atoi(string(params[0]))
|
||||
if err != nil || v < 1 || v > 5 {
|
||||
cmd.client.sendNotice("Failed to update DEFCON level: invalid level.")
|
||||
continue
|
||||
} else if v == s.defcon {
|
||||
cmd.client.sendNotice("Failed to update DEFCON level: already at specified DEFCON level.")
|
||||
continue
|
||||
}
|
||||
|
||||
lastDefcon := s.defcon
|
||||
s.defcon = v
|
||||
cmd.client.sendNotice(fmt.Sprintf("Updated DEFCON level to %d.", v))
|
||||
|
||||
if lastDefcon == 5 {
|
||||
s.clientsLock.Lock()
|
||||
for _, sc := range s.clients {
|
||||
sc.sendDefconWarning(s.defcon)
|
||||
}
|
||||
s.clientsLock.Unlock()
|
||||
}
|
||||
case bgammon.CommandShutdown:
|
||||
if !cmd.client.Admin() {
|
||||
cmd.client.sendNotice("Access denied.")
|
||||
|
|
Loading…
Reference in a new issue