@ -22,118 +22,118 @@ import (
)
const (
COMMAND_HELP = "HELP"
COMMAND_INFO = "INFO"
commandHelp = "HELP"
commandInfo = "INFO"
// User commands
COMMAND_REGISTER = "REGISTER"
COMMAND_IDENTIFY = "IDENTIFY"
COMMAND_TOKEN = "TOKEN"
COMMAND_USERNAME = "USERNAME"
COMMAND_PASSWORD = "PASSWORD"
commandRegister = "REGISTER"
commandIdentify = "IDENTIFY"
commandToken = "TOKEN"
commandUsername = "USERNAME"
commandPassword = "PASSWORD"
// User/channel commands
COMMAND_MODE = "MODE"
commandMode = "MODE"
// Channel/server commands
COMMAND_FOUND = "FOUND"
COMMAND_DROP = "DROP"
COMMAND_GRANT = "GRANT"
COMMAND_REVEAL = "REVEAL"
COMMAND_KICK = "KICK"
COMMAND_BAN = "BAN"
COMMAND_AUDIT = "AUDIT"
commandFound = "FOUND"
commandDrop = "DROP"
commandGrant = "GRANT"
commandReveal = "REVEAL"
commandKick = "KICK"
commandBan = "BAN"
commandAudit = "AUDIT"
// Server admin commands
COMMAND_KILL = "KILL"
COMMAND_STATS = "STATS"
COMMAND_REHASH = "REHASH"
COMMAND_UPGRADE = "UPGRADE"
commandKill = "KILL"
commandStats = "STATS"
commandRehash = "REHASH"
commandUpgrade = "UPGRADE"
)
var serverCommands = [ ] string { COMMAND_KILL, COMMAND_STATS , COMMAND_REHASH , COMMAND_UPGRADE }
var serverCommands = [ ] string { commandKill, commandStats , commandRehash , commandUpgrade }
// TODO: Reorder
const (
PERMISSION_CLIENT = 0
PERMISSION_REGISTERED = 1
PERMISSION_ VIP = 2
PERMISSION_MODERATOR = 3
PERMISSION_ADMIN = 4
PERMISSION_SUPERADMIN = 5
permissionClient = 0
permissionRegistered = 1
permission VIP = 2
permissionModerator = 3
permissionAdmin = 4
permissionSuperAdmin = 5
)
var permissionLabels = map [ int ] string {
PERMISSION_CLIENT : "Client" ,
PERMISSION_REGISTERED : "Registered Client" ,
PERMISSION_ VIP: "VIP" ,
PERMISSION_MODERATOR : "Moderator" ,
PERMISSION_ADMIN : "Administrator" ,
PERMISSION_SUPERADMIN : "Super Administrator" ,
permissionClient : "Client" ,
permissionRegistered : "Registered Client" ,
permission VIP: "VIP" ,
permissionModerator : "Moderator" ,
permissionAdmin : "Administrator" ,
permissionSuperAdmin : "Super Administrator" ,
}
var ALL_PERMISSIONS = "Client, Registered Client, VIP, Moderator, Administrator and Super Administrator"
var allPermissions = "Client, Registered Client, VIP, Moderator, Administrator and Super Administrator"
var commandRestrictions = map [ int ] [ ] string {
PERMISSION_REGISTERED: { COMMAND_TOKEN , COMMAND_USERNAME , COMMAND_PASSWORD , COMMAND_FOUND } ,
PERMISSION_MODERATOR: { COMMAND_MODE , COMMAND_REVEAL , COMMAND_KICK , COMMAND_BAN } ,
PERMISSION_ADMIN: { COMMAND_GRANT , COMMAND_AUDIT } ,
PERMISSION_SUPERADMIN: { COMMAND_DROP , COMMAND_KILL , COMMAND_STATS , COMMAND_REHASH , COMMAND_UPGRADE } }
permissionRegistered: { commandToken , commandUsername , commandPassword , commandFound } ,
permissionModerator: { commandMode , commandReveal , commandKick , commandBan } ,
permissionAdmin: { commandGrant , commandAudit } ,
permissionSuperAdmin: { commandDrop , commandKill , commandStats , commandRehash , commandUpgrade } }
var helpDuration = "Duration can be 0 to never expire, or e.g. 30m, 1h, 2d, 3w"
var commandUsage = map [ string ] [ ] string {
COMMAND_HELP : { "[command|all]" ,
commandHelp : { "[command|all]" ,
"Print usage information regarding a specific command or 'all'" ,
"Without a command or 'all', only commands you have permission to use are printed" } ,
COMMAND_INFO : { "[channel]" ,
commandInfo : { "[channel]" ,
"When a channel is specified, prints info including whether it is registered" ,
"Without a channel, server info is printed" } ,
COMMAND_REGISTER : { "<username> <password>" ,
commandRegister : { "<username> <password>" ,
"Create an account" ,
"Once you've registered, other users may GRANT permissions to you, or " ,
"See IDENTIFY" } ,
COMMAND_IDENTIFY : { "[username] <password>" ,
commandIdentify : { "[username] <password>" ,
"Identify to a previously registered account" ,
"If username is omitted, it will be replaced with your current nick" ,
"Note that you may automatically identify when connecting by specifying a server password of your username and password separated by a colon - Example: admin:hunter2" } ,
COMMAND_TOKEN : { "<channel>" ,
commandToken : { "<channel>" ,
"Returns a token which can be used by channel administrators to grant special access to your account" } ,
COMMAND_USERNAME : { "<username> <password> <new username> <confirm new username>" ,
commandUsername : { "<username> <password> <new username> <confirm new username>" ,
"Change your username" } ,
COMMAND_PASSWORD : { "<username> <password> <new password> <confirm new password>" ,
commandPassword : { "<username> <password> <new password> <confirm new password>" ,
"Change your password" } ,
COMMAND_FOUND : { "<channel>" ,
commandFound : { "<channel>" ,
"Take ownership of an unfounded channel" } ,
COMMAND_GRANT : { "<channel> [account] [permission]" ,
commandGrant : { "<channel> [account] [permission]" ,
"When an account token isn't specified, all accounts with permissions are listed" ,
"Specify an account token and permission level to grant that permission" ,
"Specify an account token only to view that account's permission" ,
"To remove an account's permissions, set their permission to Client" ,
"Permissions: " + ALL_PERMISSIONS } ,
COMMAND_REVEAL : { "<channel> [page] [all]" ,
"Permissions: " + allPermissions } ,
commandReveal : { "<channel> [page] [all]" ,
"Print channel log, allowing KICK/BAN to be used" ,
fmt . Sprintf ( "Results start at page 1, %d per page" , CHANNEL_LOGS_PER_PAGE ) ,
fmt . Sprintf ( "Results start at page 1, %d per page" , logsPerPage ) ,
"Page -1 shows all matching entries" ,
"Joins and parts are hidden by default, add 'all' to show them" } ,
COMMAND_AUDIT : { "<channel> [page]" ,
commandAudit : { "<channel> [page]" ,
"Print channel audit log" ,
fmt . Sprintf ( "Results start at page 1, %d per page" , CHANNEL_LOGS_PER_PAGE ) ,
fmt . Sprintf ( "Results start at page 1, %d per page" , logsPerPage ) ,
"Page -1 shows all matching entries" } ,
COMMAND_KICK : { "<channel> <5 digit log number> [reason]" ,
commandKick : { "<channel> <5 digit log number> [reason]" ,
"Kick a user from a channel" } ,
COMMAND_BAN : { "<channel> <5 digit log number> <duration> [reason]" ,
commandBan : { "<channel> <5 digit log number> <duration> [reason]" ,
"Kick and ban a user from a channel" ,
helpDuration } ,
COMMAND_DROP : { "<channel> <confirm channel>" ,
commandDrop : { "<channel> <confirm channel>" ,
"Delete all channel data, allowing it to be founded again" } ,
COMMAND_KILL : { "<channel> <5 digit log number> <duration> [reason]" ,
commandKill : { "<channel> <5 digit log number> <duration> [reason]" ,
"Disconnect and ban a user from the server" ,
helpDuration } ,
COMMAND_STATS : { "" ,
commandStats : { "" ,
"Print the current number of clients and channels" } ,
COMMAND_REHASH : { "" ,
commandRehash : { "" ,
"Reload the server configuration" } ,
COMMAND_UPGRADE : { "" ,
commandUpgrade : { "" ,
"Upgrade the server without disconnecting clients" } ,
}
@ -333,11 +333,11 @@ func (s *Server) canJoin(c *Client, channel string, key string) (bool, string) {
}
permission := c . globalPermission ( )
requiredPermission := PERMISSION_CLIENT
requiredPermission := permissionClient
reason := ""
if channel [ 0 ] == '&' {
if permission < PERMISSION_ VIP {
if permission < permission VIP {
return false , "restricted channel"
}
} else if channel [ 0 ] != '#' {
@ -351,7 +351,7 @@ func (s *Server) canJoin(c *Client, channel string, key string) (bool, string) {
}
}
if permission < PERMISSION_ VIP {
if permission < permission VIP {
if ch . hasMode ( "k" ) && ch . getMode ( "k" ) != key {
return false , "invalid channel key specified"
} else if ch . hasMode ( "l" ) {
@ -369,11 +369,11 @@ func (s *Server) canJoin(c *Client, channel string, key string) (bool, string) {
}
if ch . hasMode ( "r" ) {
requiredPermission = PERMISSION_REGISTERED
requiredPermission = permissionRegistered
reason = "only registered clients are allowed"
}
if ch . hasMode ( "i" ) {
requiredPermission = PERMISSION_ VIP
requiredPermission = permission VIP
reason = "only VIP are allowed"
}
@ -600,8 +600,8 @@ func (s *Server) handleTopic(channel string, client string, topic string) {
chp , err := db . GetPermission ( cl . account , channel )
if err != nil {
log . Panicf ( "%+v" , err )
} else if ch . hasMode ( "t" ) && chp . Permission < PERMISSION_ VIP {
cl . accessDenied ( PERMISSION_ VIP)
} else if ch . hasMode ( "t" ) && chp . Permission < permission VIP {
cl . accessDenied ( permission VIP)
return
}
@ -627,8 +627,8 @@ func (s *Server) handleChannelMode(c *Client, params []string) {
// Send channel creation time
c . writeMessage ( strings . Join ( [ ] string { "329" , c . nick , params [ 0 ] , fmt . Sprintf ( "%d" , int32 ( ch . created ) ) } , " " ) , [ ] string { } )
} else if len ( params ) > 1 && ( params [ 1 ] == "" || params [ 1 ] [ 0 ] == '+' || params [ 1 ] [ 0 ] == '-' ) {
if ! c . canUse ( COMMAND_MODE , params [ 0 ] ) {
c . accessDenied ( c . permissionRequired ( COMMAND_MODE ) )
if ! c . canUse ( commandMode , params [ 0 ] ) {
c . accessDenied ( c . permissionRequired ( commandMode ) )
return
}
@ -754,7 +754,7 @@ func (s *Server) sendUsage(cl *Client, command string) {
showAll := false
if command == "ALL" {
command = COMMAND_HELP
command = commandHelp
showAll = true
}
@ -766,7 +766,7 @@ func (s *Server) sendUsage(cl *Client, command string) {
var printedLabel bool
var usage [ ] string
if command == COMMAND_HELP {
if command == commandHelp {
// Print all commands
var perms [ ] int
for permission := range permissionLabels {
@ -844,7 +844,7 @@ func (s *Server) ban(channel string, iphash string, accountid int64, expires int
ch := channel
rs := formatAction ( "Banned" , reason )
if channel == CHANNEL_SERVER {
if channel == channelServer {
ch = ""
rs = formatAction ( "Killed" , reason )
}
@ -855,7 +855,7 @@ func (s *Server) ban(channel string, iphash string, accountid int64, expires int
}
if ( iphash != "" && cl . iphash == iphash ) || ( accountid > 0 && cl . account == accountid ) {
if channel == CHANNEL_SERVER {
if channel == channelServer {
cl . writeMessage ( irc . KILL , [ ] string { cl . nick , rs } )
s . killClient ( cl , rs )
} else {
@ -885,14 +885,14 @@ func (s *Server) handleUserCommand(client string, command string, params []strin
}
switch command {
case COMMAND_HELP :
case commandHelp :
cmd := command
if len ( params ) > 0 {
cmd = params [ 0 ]
}
s . sendUsage ( cl , cmd )
return
case COMMAND_INFO :
case commandInfo :
if len ( params ) > 0 && len ( params [ 0 ] ) > 0 {
if ! s . inChannel ( params [ 0 ] , client ) {
if canaccess , reason := s . canJoin ( cl , params [ 0 ] , "" ) ; ! canaccess {
@ -917,7 +917,7 @@ func (s *Server) handleUserCommand(client string, command string, params []strin
cl . sendMessage ( "AnonIRCd https://github.com/sageru-6ch/anonircd" )
}
return
case COMMAND_REGISTER :
case commandRegister :
if len ( params ) == 0 {
s . sendUsage ( cl , command )
return
@ -925,7 +925,7 @@ func (s *Server) handleUserCommand(client string, command string, params []strin
// TODO: Only alphanumeric username
// TODO: allow duplicate usernames, only return error on existing username and password
case COMMAND_IDENTIFY :
case commandIdentify :
if len ( params ) == 0 || len ( params ) > 2 {
s . sendUsage ( cl , command )
return
@ -941,8 +941,8 @@ func (s *Server) handleUserCommand(client string, command string, params []strin
authSuccess := cl . identify ( username , password )
if authSuccess {
cl . sendNotice ( "Identified successfully" )
if cl . globalPermission ( ) >= PERMISSION_ VIP {
s . joinChannel ( cl . identifier , CHANNEL_SERVER , "" )
if cl . globalPermission ( ) >= permission VIP {
s . joinChannel ( cl . identifier , channelServer , "" )
}
for clch := range s . getChannels ( cl . identifier ) {
@ -959,7 +959,7 @@ func (s *Server) handleUserCommand(client string, command string, params []strin
} else {
cl . sendNotice ( "Failed to identify, incorrect username/password" )
}
case COMMAND_USERNAME :
case commandUsername :
if cl . account == 0 {
cl . sendError ( "You must identify before using that command" )
}
@ -990,7 +990,7 @@ func (s *Server) handleUserCommand(client string, command string, params []strin
log . Panicf ( "%+v" , err )
}
cl . sendMessage ( "Username changed successfully" )
case COMMAND_PASSWORD :
case commandPassword :
if len ( params ) == 0 || len ( params ) < 4 {
s . sendUsage ( cl , command )
return
@ -1016,7 +1016,7 @@ func (s *Server) handleUserCommand(client string, command string, params []strin
log . Panicf ( "%+v" , err )
}
cl . sendMessage ( "Password changed successfully" )
case COMMAND_REVEAL, COMMAND_AUDIT :
case commandReveal, commandAudit :
if len ( params ) == 0 {
s . sendUsage ( cl , command )
return
@ -1050,12 +1050,12 @@ func (s *Server) handleUserCommand(client string, command string, params []strin
}
}
if command == COMMAND_REVEAL {
if command == commandReveal {
s . revealChannelLog ( params [ 0 ] , cl . identifier , page , all )
} else {
// TODO: Audit
}
case COMMAND_KICK :
case commandKick :
if len ( params ) < 2 {
s . sendUsage ( cl , command )
return
@ -1079,7 +1079,7 @@ func (s *Server) handleUserCommand(client string, command string, params []strin
}
s . partChannel ( ch . identifier , rcl . identifier , reason )
cl . sendMessage ( fmt . Sprintf ( "Kicked %s %s" , params [ 0 ] , params [ 1 ] ) )
case COMMAND_BAN, COMMAND_KILL :
case commandBan, commandKill :
if len ( params ) < 3 {
s . sendUsage ( cl , command )
return
@ -1111,8 +1111,8 @@ func (s *Server) handleUserCommand(client string, command string, params []strin
}
bch := ch . identifier
if command == COMMAND_KILL {
bch = CHANNEL_SERVER
if command == commandKill {
bch = channelServer
}
err := s . ban ( bch , rcl . iphash , rcl . account , expires , reason )
if err != nil {
@ -1121,9 +1121,9 @@ func (s *Server) handleUserCommand(client string, command string, params []strin
}
cl . sendMessage ( fmt . Sprintf ( "%sed %s %s" , strings . Title ( strings . ToLower ( command ) ) , params [ 0 ] , params [ 1 ] ) )
case COMMAND_STATS :
case commandStats :
cl . sendMessage ( fmt . Sprintf ( "%d clients in %d channels" , s . clientCount ( ) , s . channelCount ( ) ) )
case COMMAND_REHASH :
case commandRehash :
err := s . reload ( )
if err != nil {
@ -1131,7 +1131,7 @@ func (s *Server) handleUserCommand(client string, command string, params []strin
} else {
cl . sendMessage ( "Reloaded configuration" )
}
case COMMAND_UPGRADE :
case commandUpgrade :
// TODO
}
}
@ -1166,7 +1166,7 @@ func (s *Server) handlePrivmsg(target string, client string, message string) {
ch := s . getChannel ( target )
if ch == nil {
return
} else if ch . hasMode ( "m" ) && cl . getPermission ( target ) < PERMISSION_ VIP {
} else if ch . hasMode ( "m" ) && cl . getPermission ( target ) < permission VIP {
cl . writeMessage ( irc . ERR_CANNOTSENDTOCHAN , [ ] string { target , fmt . Sprintf ( "Channel is moderated, only VIP may speak (%s)" , target ) } )
return
}
@ -1185,7 +1185,7 @@ func (s *Server) handlePrivmsg(target string, client string, message string) {
func ( s * Server ) handleRead ( c * Client ) {
for {
if c . state == ENTITY_STATE_TERMINATING {
if c . state == stateTerminating {
return
}
@ -1196,7 +1196,7 @@ func (s *Server) handleRead(c *Client) {
c . conn . SetReadDeadline ( time . Now ( ) . Add ( 300 * time . Second ) )
msg , err := c . reader . Decode ( )
if c . state == ENTITY_STATE_TERMINATING {
if c . state == stateTerminating {
return
} else if msg == nil || err != nil {
// Error decoding message, client probably disconnected
@ -1217,7 +1217,7 @@ func (s *Server) handleRead(c *Client) {
c . writeMessage ( irc . RPL_WELCOME , [ ] string { "Welcome to AnonIRC " + c . getPrefix ( ) . String ( ) } )
c . writeMessage ( irc . RPL_YOURHOST , [ ] string { "Your host is AnonIRC, running version AnonIRCd https://github.com/sageru-6ch/anonircd" } )
c . writeMessage ( irc . RPL_CREATED , [ ] string { fmt . Sprintf ( "This server was created %s" , time . Unix ( s . created , 0 ) . UTC ( ) ) } )
c . writeMessage ( strings . Join ( [ ] string { irc . RPL_MYINFO , c . nick , "AnonIRC" , "AnonIRCd" , CLIENT_MODES, CHANNEL_MODES , CHANNEL_MODES_ARG } , " " ) , [ ] string { } )
c . writeMessage ( strings . Join ( [ ] string { irc . RPL_MYINFO , c . nick , "AnonIRC" , "AnonIRCd" , clientModes, channelModes , channelModesWithArg } , " " ) , [ ] string { } )
for i , motdmsg := range s . motd {
var motdcode string
@ -1231,9 +1231,9 @@ func (s *Server) handleRead(c *Client) {
c . writeMessage ( motdcode , [ ] string { " " + motdmsg } )
}
s . joinChannel ( c . identifier , CHANNEL_LOBBY , "" )
if c . globalPermission ( ) >= PERMISSION_ VIP {
s . joinChannel ( c . identifier , CHANNEL_SERVER , "" )
s . joinChannel ( c . identifier , channelLobby , "" )
if c . globalPermission ( ) >= permission VIP {
s . joinChannel ( c . identifier , channelServer , "" )
}
} else if msg . Command == irc . PASS && c . user == "" && len ( msg . Params ) > 0 && len ( msg . Params [ 0 ] ) > 0 {
// TODO: Add auth and multiple failed attempts ban
@ -1301,7 +1301,7 @@ func (s *Server) handleRead(c *Client) {
key := k . ( string )
ch := v . ( * Channel )
if key [ 0 ] == '&' && c . globalPermission ( ) < PERMISSION_ VIP {
if key [ 0 ] == '&' && c . globalPermission ( ) < permission VIP {
return true
}
@ -1419,7 +1419,7 @@ func (s *Server) handleConnection(conn net.Conn, ssl bool) {
banned := true
reason := ""
if c != nil {
banned , reason = c . isBanned ( CHANNEL_SERVER )
banned , reason = c . isBanned ( channelServer )
}
go s . handleWrite ( c )
@ -1435,10 +1435,10 @@ func (s *Server) handleConnection(conn net.Conn, ssl bool) {
}
func ( s * Server ) killClient ( c * Client , reason string ) {
if c == nil || c . state == ENTITY_STATE_TERMINATING {
if c == nil || c . state == stateTerminating {
return
}
c . state = ENTITY_STATE_TERMINATING
c . state = stateTerminating
if _ , ok := s . clients . Load ( c . identifier ) ; ok {
s . partAllChannels ( c . identifier , reason )
@ -1571,7 +1571,7 @@ func (s *Server) loadConfig() error {
return errors . New ( fmt . Sprintf ( "DBDriver and DBSource must be configured in %s\nExample:\n\nDBDriver=\"sqlite3\"\nDBSource=\"/home/user/anonircd/anonircd.db\"" , s . configfile ) )
}
motd := DEFAULT_ MOTD
motd := default MOTD
if s . config . MOTD != "" {
motd = s . config . MOTD
}