Difference between revisions of "Login and user system"

From Scriptwiki
Jump to: navigation, search
m (added category)
m (changed text a bit)
Line 25: Line 25:
 
If you wish to use named levels, like Master, Owner, etc. you'll need to add those levels with corresponding numbered level into the '''cuser''' alias, see the source for more info.
 
If you wish to use named levels, like Master, Owner, etc. you'll need to add those levels with corresponding numbered level into the '''cuser''' alias, see the source for more info.
  
I added events for user control via query to the examples part, so you can add the script to your bot and use the commands via query.
+
I added events for user control to the examples part, so you can add the script to your bot and use the commands via query/channel with !command.
  
 
  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

Revision as of 09:11, 11 July 2007

A user system with accesslevels and user control.
The main idea of this script is to identify users through a login, not like mirc's default accesslevels, by nick/ident/host or some of those combinations.
Here it doesn't matter what nick/ident/host the user has, he just logs into the bot.

Commands:

  • /loadusers = makes the users and login tables, and loads saved user information.
  • /saveusers = saves user information to users.hsh and frees users and login tables.
  • /adduser = adds a new user (/adduser <username> <password>
  • /deluser = deletes an existing user /deluser <username>)
  • /userlist = gives you a list of users (/userlist <-all|-active> -all = all of the users, -active = list only logged in users)
  • /edituser = edits users information (/edituser <-pass|-username|-addlevel|-remlevel|-help> <username> <parameters>)
  • /logoutusers = logs out all users from a given channel (/logoutusers #chan, used when you part/get kicked)

Identifiers:

  • $checklevel = checks if the user has sufficient accesslevel, returns $true/$false ($checklevel($address,$chan,master))
  • $getlevel = return the users level, numbered/named ($getlevel($address,$chan|Global))
  • $getuser = returns username by given address ($getuser($address))

A little more explanation on how this works:
The user can have an acceslevels on a channel, and a global accesslevel, when checking for a level on certain channel, and it's insufficient, then the global level is checked.
ie. you have a command !op, which requires atleast level 10 to use it, $checklevel($address,$chan,10) is then used, if the user has accesslevel of 5 on that channel, but he has a Global level of 15, he can use the command.
You can also check only for a global level by doing $checklevel($address,global,10), and if you only want to know, if the user is logged in, you can use $checklevel($address).

If you want to compare the exact level of the user, use $getlevel($address,$chan) ($chan or "global") in an if like: if ($getlevel($address,$chan) == Master) { notice $nick yes, you are a master on $chan }
If you wish to use named levels, like Master, Owner, etc. you'll need to add those levels with corresponding numbered level into the cuser alias, see the source for more info.

I added events for user control to the examples part, so you can add the script to your bot and use the commands via query/channel with !command.

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Usersystem with accesslevels and user control.
;; Contact: Cail @ QuakeNet -> #help.script
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

alias loadusers {
 ; check if 'users' and 'login' tables already exist, if not, create them
 if (!$hget(users)) { hmake users 100 }
 if (!$hget(login)) { hmake login 100 }

 ; check if there is a file 'users.hsh' (saved user information), if we have it, empty users-table and load the saved info
 if ($is_file(users.hsh)) { hdel -w users * | hload users users.hsh }
}

alias saveusers {
 ; check if 'users' and 'login' tables even exist, if so, they can be saved and freed
 if ($hget(users)) { hsave users users.hsh | .hfree users }
 if ($hget(login)) { hfree login }
}

alias -l logoutusers {
 ; loop through a given channel ($1 = channel) and logout everyone who is logged in

 var %x = 1 
 while ($nick($1,%x)) { 
   var %addr = $v1 

   ; check the login table for a matching address with $ial().addr, and if he's not on any other same channels as you
   if ($hget(login,$ial(%addr).addr)) && (!$comchan(%addr,2)) { hdel login %addr } 
   inc %x 
 }
}

alias cuser {
 ; return corresponding accesslevel for named levels, needed for comparison

 if ($1 == owner) { return 200 }
 elseif ($1 == master) { return 150 }
 elseif ($1 == test) { return 100 }
 else { return $1 }
}

alias checklevel {
 ; if $2 ('#channel' or 'global') isn't given, check if the user is logged in
 if (!$2) { return $iif($hget(login,$1),$true,$false) }

 ; fetch the username to %user from the login table by $1 (given address),
 ; %lvl_chan and %lvl_global will get their values from the users-table, converted to a numeric with $cuser
 ; $iif gives them value 0 if they don't exist (comparison won't work with $null)
 var %user = $hget(login,$1)
 var %lvl_chan = $iif($cuser($hget(users,$+(%user,$chr(7),$2))),$v1,0)
 var %lvl_global = $iif($cuser($hget(users,$+(%user,$chr(7),global))),$v1,0)

 ; inner $iif checks which one is greater, channel level or global level, and compares it to given level ($3)
 return $iif($iif(%lvl_global > %lvl_chan,%lvl_global,%lvl_chan) >= $cuser($3),$true,$false)
}

alias getlevel {
 ; return the named level by given address
 return $hget(users,$+($hget(login,$1),$chr(7),$2))
}

alias getuser { 
 ; return username by given address
 return $hget(login,$1) 
}

alias adduser {
 ; errorchecking
 ; check if the users-table exist
 if (!$hget(users)) { var %error = You need to load the usertable first: /loadusers }
 ; check if there's enough parameters
 if (!$2) { var %error = Insufficient parameters, usage: /adduser <username> <password> }
 ; check if given username doesn't exist
 if ($hget(users,$1)) { var %error = That username is already taken! }
 ; validate the username and password
 if (!$regex($+($1,$2),/^([][A-Za-z\\^`{|}-][][\w\\^`{|}-]*)$/)) { var %error = Incorrect username. }

 ; if we encountered an error return the error msg or echo it, depending of if it was called as an identifier or not
 ; else say that everything's fine
 if (%error) { echo -ag %error | return %error } 

 ; everything was fine if we got here, add the user into users table and save the table
 hadd users $1 $2
 hsave users users.hsh 
 echo -ag User $1 added.
 return User $1 added.
}

alias edituser {
 ; errorchecking
 ; check if valid parameters are given ($1 = switch, $2 = username, $3- = parameters)
 if (!$istok(-pass -addlevel -remlevel -username -help,$1,32)) || (!$3) { 
   var %error Usage: /edituser <-pass|-addlevel|-remlevel|-username|-help> <username> <parameters>
 }
 ; check if the user exists
 elseif (!$hget(users,$2)) { var %error No such user. }

 ; echo/return errors if any, else carry on
 if (%error) { echo -ag %error | return %error }

 ; get the address from the login-table, and check if the address is found from IAL, if so, we can msg the user with the changes made
 var %nick = $ial($+(*,$hfind(login,$2,1).data),1).nick

 ; -pass: changes the users password
 if ($1 == -pass) {
   ; check the validity of the password
   if (!$regex($3,/^([][A-Za-z\\^`{|}-][][\w\\^`{|}-]*)$/)) { var %error Incorrect password. }

   ; check for errors
   if (%error) { echo -ag %error | return %error }

   ; everything's fine, add the new password to the users table, echo, and msg %nick (if found)
   hadd users $2 $3 
   if (%nick) { .notice $v1 Your password has been changed to $3 }
   echo -ag Changed $2 $+ 's password to $3 
   return Changed $2 $+ 's password to $3
 }

 ; -addlevel: add access level to user, for #channel or Global
 elseif ($1 == -addlevel) {
   ; here we have more parameters, so we need to check that there is $4
   if ($4 == $null) { var %error Usage: /edituser -addlevel username #channel|global accesslevel }

   ; check for errors
   if (%error) { echo -ag %error | return %error }

   ; add a new item into users-table (username7#channel) that 7 in there is $chr(7), we use it to separate username and channel in the item name
   ; then again echo and msg %nick if possible
   hadd users $+($2,$chr(7),$3) $4
   if (%nick) { .notice $v1 Your $3 accesslevel has been changed to $4 $+ . }
   echo -ag Changed $2 $+ 's level to > $3 $+ : $4
   return Changed $2 $+ 's level to > $3 $+ : $4
 }

 ; -remlevel: remove a users level
 elseif ($1 == -remlevel) {
   ; check that the user has accesslevels in $3 (given channel/Global)
   if (!$hget(users,$+($2,$chr(7),$3))) { var %error = User $2 doesn't have accesslevel in $3 }

   ; check for errors
   if (%error) { echo -ag %error | return %error }

   ; hdel the item from users-table, echo, and msg %nick if possible
   hdel users $+($2,$chr(7),$3) 
   if (%nick) { .notice $v1 Your accesslevel in $3 has been removed. }
   echo -ag Removed $2 $+ 's accesslevel from $3
   return Removed $2 $+ 's accesslevel from $3
 }

 ; -username: change the username of someone (this is case-insensitive, so you cannot change ie. Cail -> cail)
 elseif ($1 == -username) {
   ; check that the new username isn't already taken, and validate the new username
   if ($hget(users,$3)) { var %error = That username is already taken! }
   if (!$regex($3,/^([][A-Za-z\\^`{|}-][][\w\\^`{|}-]*)$/)) { var %error = Incorrect username. }

   ; check for errors
   if (%error) { echo -ag %error | return %error }

   ; we need to store the address to a variables, 'cause we will be deleting the old item from the login-table
   var %pass = $hget(users,$2)
   var %address = $hfind(login,$2,1).data

   ; add the new username with the old password, and delete the old item
   hadd users $3 $hget(users,$2)
   hdel users $2 

   ; update all the access levels for the new username, %y = the number of accesslevel items
   var %y = $hfind(users,$+($2,$chr(7),*),0,w)
   while (%y) {
     ; use $hfind to get the old item name
     var %item = $hfind(users,$+($2,$chr(7),*),%y,w)

     ; add the new itemname with the old value, and delete the old item
     hadd users $+($3,$chr(7),$gettok(%item,2-,7)) $hget(users,%item)
     hdel users %item
     dec %y
   }

   ; change the username in the login-table, if the user is logged in, and msg him with the changes
   if (%address) { hadd login %address $3 }
   if (%nick) { .notice $v1 Your username has been changed to $3 $+ . }
   echo -ag Changed $2 $+ 's username to $3
   return Changed $2 $+ 's username to $3
 }

 ; -help: echo the syntax of /edituser
 elseif ($1 == -help) {
   echo -ag -pass -> /edituser -pass <username> <new_password>
   echo -ag -addlevel -> /edituser -addlevel <username> <#channel|global> <level>
   echo -ag -remlevel -> /edituser -remlevel <username> <#channel|global>
   echo -ag -username -> /edituser -username <username> <new_username>
   echo -ag If level is a named level, make sure you have added it into the cuser -alias.
 }

 ; we have made some changes to the users-table, save it now
 hsave users users.hsh
}

alias deluser {
 ; check that given username exists
 if (!$hget(users,$1)) { var %error No such user. }

 ; check for errors
 if (%error) { echo -ag %error | return %error }

 ; delete the username from the userstable and remove all of his accesslevels, and echo the progress
 ; and if he is logged in, remove him from the login-table
 hdel users $1
 hdel -w users $+($1,$chr(7),*)
 if ($hfind(login,12,1).data) { hdel login $v1 }
 echo -ag Removed user $1
 return Removed user $1
}

alias userlist {
 ; check that given input is correct
 if (!$istok(-all -active,$1,32)) { echo -ag Usage: /userlist <-all|-active> | return }

 ; make variable %active $true/$false depending on if we're looking for active users
 var %active = $iif($1 == -active,$true,$false)

 ; echo an empty line and "listing blaa blaa"
 echo -ag $chr(160)
 echo -ag --- Listing $remove($1,-) users:

 ; the regular expression in the $hfind finds all the items, that doesn't have $chr(7) in the itemname (we don't want to mix accesslevel items with username items)
 var %x = 1 
 while ($hfind(users,/^[^\x07]+$/i,%x,r)) { 
   ; put the username into a variable, if the user is logged in, %address will hold his address, assign %levels variable to $null at the start
   var %user = $v1
   var %address = $hfind(login,%user,1).data
   var %levels = $null

   ; if we are looking for active users %active will now be $true, and if there's no %address, the user isn't logged in, so /continue and keep looking for users
   if (%active) && (!%address) { inc %x | continue }

   ; echo username and address/"not logged", $base() here will zero-pad the number (2 becomes 02, looks better)
   echo -ag $chr(31) $+ $base(%x,10,10,2) $+ : %user ( $+ $iif(%address,%address,not logged) $+ ) $chr(31) 

   ; now that we have a user, loop through all of his accesslevels (now we want to find everyitem starting with username7, where the 7 is again $chr(7))
   var %y = 1
   while ($hfind(users,$+(%user,$chr(7),*),%y,w)) {
     ; put the levels into %levels variable, so we can echo all of them on one line (well put $chr(7) here to separate the "#channel: level" from "#channel2: level2" so we can sort them later)
     var %levels = $gettok($v1,2-,7) $+ : $hget(users,$v1) $+ $chr(7) $+ %levels
     inc %y
   }

   ; so we have all the levels the user has in %levels, now $sorttok so we get the Global-level first, and replace that $chr(7) with spaces and -
   ; we would get a line like: Global: Master - #channel: Owner etc.
   echo -ag $str($chr(160),3) Levels: $replace($sorttok(%levels,7,r),$chr(7),$+($chr(32),-,$chr(32)))
   inc %x 
 }

 ; echo "end of" and an empty line
 echo -ag --- End of users.
 echo -ag $chr(160)
}

; EVENTS

on *:start:{ loadusers }
on *:exit:{ saveusers }

on !*:quit:{ 
 ; if the user that quit, was logged in, remove him from the login table
 if ($hget(login,$address)) { hdel login $address } 
}

on *:part:#:{ 
 ; if it is you, who parts the channel, logout everyone in that channel (if they're not on some other channels, where you are)
 ; else check if the user that quit, is logged in (and is not on any other chans with you), log him out

 if ($nick == $me) { logoutusers # }
 elseif ($hget(login,$address)) && (!$comchan($nick,2)) { hdel login $address } 
}

on *:kick:#:{ 
 ; if it is you, who got kicked, logout everyone in that channel (if they're not on some other channels, where you are)
 ; else check if the user that got kicked, is logged in (and is not on any other chans with you), log him out

 if ($knick == $me) { logoutusers # }
 elseif ($hget(login,$address)) && (!$comchan($knick,2)) { hdel login $address } 
}

on ^*:open:?:login & &:{
 ; check if user is already logged in, if so, tell him that
 if ($hget(login,$address)) {
   .notice $nick You are already logged in!
 }
 ; check that the user is on atleast one channel with you
 elseif (!$comchan($nick,0)) { 
   .notice $nick You need to be on atleast one same channel as i am to login. 
 }
 ; if the login information is correct (check that item $2 has the right password $3), add the user into login-table
 elseif ($hget(users,$2) == $3) {
   .notice $nick succesfully logged in
   hadd login $address $2
 }
 ; else the login information is incorrect
 else { 
   .notice $nick Wrong username/password.
 }
 haltdef
}

Exaples of usage

on *:text:!adduser & &:*:{
 if ($getlevel($address,global) == Owner) { .notice $nick $adduser($2,$3) }
 else { .notice $nick You need to be an owner to use this command }
}

on *:text:!edituser & & *:*:{
 if ($getlevel($address,global) == Owner) { .notice $nick $edituser($2,$3,$4,$5) }
 else { .notice $nick You need to be an owner to use this command }
}

on *:text:!deluser &:*:{
 if ($getlevel($address,global) == Owner) { .notice $nick $deluser($2) }
 else { .notice $nick You need to be an owner to use this command }
}

on *:text:!opme:*:{ 
 ; we'll use $checklevel to determine if the user has atleast accesslevel of Master in $chan (or higher Global level)
 if ($checklevel($address,$chan,master)) { mode $chan +o $nick }
 else { .notice $nick You have to be atleast master to use this command. }
}

on *:text:!deopme:*:{ 
 ; and here the same, the user needs to have atleast accesslevel of 'test'
 if ($checklevel($address,$chan,test)) { mode $chan -o $nick }
 else { .notice $nick You have to be atleast at test level to use this command. }
}

on *:text:!whoami:*:{ 
 ; here we only check that is the user logged in, no other parameters given to $checklevel but the $address
 if ($checklevel($address)) { 
   ; $getuser returns the username of the user (username isn't the same as the nick)
   ; $getlevel returns the named/numbered level of the user on $chan or 'Global'

   .msg $chan You are known as $getuser($address) $+ , you have accesslevel of $iif( $getlevel($address,$chan) ,$v1,0) on $chan
   .msg $chan Your global level is $getlevel($address,Global) 
 }
 else { .notice $nick You need to login to use this command. }
}