2005-09-30 12:28:49 +02:00
//userDB.java
//-------------------------------------
//part of YACY
//(C) by Michael Peter Christen; mc@anomic.de
//first published on http://www.anomic.de
//Frankfurt, Germany, 2004
//
//This file ist contributed by Martin Thelian
//last major change: $LastChangedDate$ by $LastChangedBy$
//Revision: $LastChangedRevision$
//
//This program is free software; you can redistribute it and/or modify
//it under the terms of the GNU General Public License as published by
//the Free Software Foundation; either version 2 of the License, or
//(at your option) any later version.
//
//This program is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
//GNU General Public License for more details.
//
//You should have received a copy of the GNU General Public License
//along with this program; if not, write to the Free Software
//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
//Using this software in any meaning (reading, learning, copying, compiling,
//running) means that you agree that the Author(s) is (are) not responsible
//for cost, loss of data or any harm that may be caused directly or indirectly
//by usage of this softare or this documentation. The usage of this software
//is on your own risk. The installation and usage (starting/running) of this
//software may allow other people or application to access your computer and
//any attached devices and is highly dependent on the configuration of the
//software which must be done by the user of the software; the author(s) is
//(are) also not responsible for proper configuration and usage of the
//software, even if provoked by documentation provided together with
//the software.
//
//Any changes to this file according to the GPL as documented in the file
//gpl.txt aside this file in the shipment you received can be done to the
//lines that follows this copyright notice here, but changes must not be
//done inside the copyright notive above. A re-distribution must contain
//the intact and unchanged copyright notice.
//Contributions and changes to the program code must be marked as such.
package de.anomic.data ;
import java.io.File ;
import java.io.IOException ;
import java.util.HashMap ;
2005-09-30 15:21:31 +02:00
import java.util.HashSet ;
import java.util.Iterator ;
2005-09-30 12:28:49 +02:00
import java.util.Map ;
2005-10-10 15:06:03 +02:00
import java.util.Date ;
import java.util.Calendar ;
2005-09-30 12:28:49 +02:00
import de.anomic.kelondro.kelondroDyn ;
import de.anomic.kelondro.kelondroException ;
import de.anomic.kelondro.kelondroMap ;
import de.anomic.server.logging.serverLog ;
2005-10-14 12:53:50 +02:00
import de.anomic.server.serverCodings ;
import de.anomic.plasma.plasmaSwitchboard ;
2005-09-30 12:28:49 +02:00
2005-10-10 11:17:19 +02:00
public final class userDB {
2005-09-30 15:21:31 +02:00
2005-09-30 12:28:49 +02:00
public static final int USERNAME_MAX_LENGTH = 128 ;
public static final int USERNAME_MIN_LENGTH = 4 ;
2005-09-30 15:21:31 +02:00
kelondroMap userTable ;
2005-10-10 11:17:19 +02:00
private final File userTableFile ;
private final int bufferkb ;
2005-10-14 12:53:50 +02:00
private final serverCodings codings = new serverCodings ( true ) ;
private HashMap ipUsers = new HashMap ( ) ;
2005-09-30 12:28:49 +02:00
2005-09-30 16:56:50 +02:00
public userDB ( File userTableFile , int bufferkb ) throws IOException {
this . userTableFile = userTableFile ;
2005-09-30 12:28:49 +02:00
this . bufferkb = bufferkb ;
2005-09-30 16:56:50 +02:00
if ( userTableFile . exists ( ) ) {
2005-09-30 12:28:49 +02:00
try {
2005-09-30 16:56:50 +02:00
this . userTable = new kelondroMap ( new kelondroDyn ( userTableFile , bufferkb * 1024 ) ) ;
2005-09-30 12:28:49 +02:00
} catch ( kelondroException e ) {
2005-09-30 16:56:50 +02:00
userTableFile . delete ( ) ;
userTableFile . getParentFile ( ) . mkdirs ( ) ;
this . userTable = new kelondroMap ( new kelondroDyn ( userTableFile , bufferkb * 1024 , 128 , 256 ) ) ;
2005-09-30 12:28:49 +02:00
}
} else {
2005-09-30 16:56:50 +02:00
userTableFile . getParentFile ( ) . mkdirs ( ) ;
this . userTable = new kelondroMap ( new kelondroDyn ( userTableFile , bufferkb * 1024 , 128 , 256 ) ) ;
2005-09-30 12:28:49 +02:00
}
}
public int [ ] dbCacheChunkSize ( ) {
return userTable . cacheChunkSize ( ) ;
}
public int [ ] dbCacheFillStatus ( ) {
return userTable . cacheFillStatus ( ) ;
}
2005-09-30 15:21:31 +02:00
void resetDatabase ( ) {
2005-09-30 12:28:49 +02:00
// deletes the database and creates a new one
if ( userTable ! = null ) try {
userTable . close ( ) ;
} catch ( IOException e ) { }
if ( ! ( userTableFile . delete ( ) ) ) throw new RuntimeException ( " cannot delete user database " ) ;
try {
userTableFile . getParentFile ( ) . mkdirs ( ) ;
userTable = new kelondroMap ( new kelondroDyn ( userTableFile , this . bufferkb , 256 , 512 ) ) ;
} catch ( IOException e ) {
serverLog . logSevere ( " PLASMA " , " user.resetDatabase " , e ) ;
}
}
public void close ( ) {
try {
userTable . close ( ) ;
} catch ( IOException e ) { }
}
public int size ( ) {
return userTable . size ( ) ;
}
public void removeEntry ( String hostName ) {
try {
userTable . remove ( hostName . toLowerCase ( ) ) ;
} catch ( IOException e ) { }
}
2005-09-30 15:21:31 +02:00
public Entry getEntry ( String userName ) {
2005-09-30 12:28:49 +02:00
try {
2005-09-30 15:21:31 +02:00
Map record = userTable . get ( userName ) ;
2005-09-30 12:28:49 +02:00
if ( record = = null ) return null ;
2005-09-30 15:21:31 +02:00
return new Entry ( userName , record ) ;
2005-09-30 12:28:49 +02:00
} catch ( IOException e ) {
return null ;
}
}
2005-09-30 16:56:50 +02:00
public Entry createEntry ( String userName , HashMap userProps ) {
2005-09-30 12:28:49 +02:00
Entry entry = new Entry ( userName , userProps ) ;
return entry ;
}
public String addEntry ( Entry entry ) {
try {
userTable . set ( entry . userName , entry . mem ) ;
return entry . userName ;
} catch ( IOException e ) {
return null ;
}
}
2005-10-14 12:53:50 +02:00
/ *
* use a ProxyAuth String to authenticate a user
* @param auth a base64 Encoded String , which contains " username:pw " .
* /
public Entry proxyAuth ( String auth ) {
Entry entry = null ;
auth = auth . trim ( ) . substring ( 6 ) ;
try {
auth = codings . decodeBase64String ( auth ) ;
} catch ( StringIndexOutOfBoundsException e ) { } //no valid Base64
String [ ] tmp = auth . split ( " : " ) ;
if ( tmp . length = = 2 ) {
entry = this . getEntry ( tmp [ 0 ] ) ;
if ( entry ! = null & & entry . getMD5EncodedUserPwd ( ) . equals ( serverCodings . encodeMD5Hex ( auth ) ) ) {
return entry ;
}
}
return null ;
}
/ *
* use a ProxyAuth String to authenticate a user and save the ip / username for ipAuth
* @param auth a base64 Encoded String , which contains " username:pw " .
* @param ip an ip .
* /
public Entry proxyAuth ( String auth , String ip ) {
Entry entry = proxyAuth ( auth ) ;
if ( entry = = null ) {
return null ;
} else {
this . ipUsers . put ( ip , entry . getUserName ( ) ) ;
System . out . println ( ip + " , " + entry . getUserName ( ) ) ;
return entry ;
}
}
/ *
* authenticate a user by ip , if he had used proxyAuth in the last 10 Minutes
* @param ip the IP of the User
* /
public Entry ipAuth ( String ip ) {
System . out . println ( ip ) ;
if ( this . ipUsers . containsKey ( ip ) ) {
String user = ( String ) this . ipUsers . get ( ip ) ;
System . out . println ( user ) ;
Entry entry = this . getEntry ( user ) ;
Long entryTimestamp = entry . getLastAccess ( ) ;
if ( entryTimestamp = = null | | ( System . currentTimeMillis ( ) - entryTimestamp . longValue ( ) ) > ( 1000 * 60 * 10 ) ) { //no timestamp or older than 10 Minutes
System . out . println ( " too old " ) ;
System . out . println ( System . currentTimeMillis ( ) - entryTimestamp . longValue ( ) ) ;
return null ;
}
return entry ; //All OK
} else { //not known
return null ;
}
}
2005-09-30 12:28:49 +02:00
public class Entry {
public static final String MD5ENCODED_USERPWD_STRING = " MD5_user:pwd " ;
public static final String AUTHENTICATION_METHOD = " auth_method " ;
public static final String USER_FIRSTNAME = " firstName " ;
public static final String USER_LASTNAME = " lastName " ;
public static final String USER_ADDRESS = " address " ;
2005-09-30 16:56:50 +02:00
public static final String LAST_ACCESS = " lastAccess " ;
public static final String TIME_USED = " timeUsed " ;
public static final String TIME_LIMIT = " timeLimit " ;
2005-09-30 17:41:01 +02:00
public static final String TRAFFIC_SIZE = " trafficSize " ;
public static final String TRAFFIC_LIMIT = " trafficLimit " ;
2005-09-30 12:28:49 +02:00
// this is a simple record structure that hold all properties of a user
private Map mem ;
private String userName ;
2005-10-10 15:06:03 +02:00
private Calendar oldDate , newDate ;
2005-09-30 12:28:49 +02:00
public Entry ( String userName , Map mem ) {
if ( ( userName = = null ) | | ( userName . length ( ) = = 0 ) )
throw new IllegalArgumentException ( ) ;
this . userName = userName . trim ( ) ;
2005-09-30 17:41:01 +02:00
if ( this . userName . length ( ) < USERNAME_MIN_LENGTH )
2005-09-30 12:28:49 +02:00
throw new IllegalArgumentException ( " Username to short. Length should be >= " + USERNAME_MIN_LENGTH ) ;
2005-09-30 15:21:31 +02:00
2005-09-30 12:28:49 +02:00
if ( mem = = null ) this . mem = new HashMap ( ) ;
else this . mem = mem ;
if ( ! mem . containsKey ( AUTHENTICATION_METHOD ) ) this . mem . put ( AUTHENTICATION_METHOD , " yacy " ) ;
2005-10-10 15:06:03 +02:00
this . oldDate = Calendar . getInstance ( ) ;
this . newDate = Calendar . getInstance ( ) ;
2005-09-30 12:28:49 +02:00
}
public String getUserName ( ) {
return this . userName ;
}
public String getFirstName ( ) {
return ( this . mem . containsKey ( USER_FIRSTNAME ) ? ( String ) this . mem . get ( USER_FIRSTNAME ) : null ) ;
}
public String getLastName ( ) {
return ( this . mem . containsKey ( USER_LASTNAME ) ? ( String ) this . mem . get ( USER_LASTNAME ) : null ) ;
}
public String getAddress ( ) {
return ( this . mem . containsKey ( USER_ADDRESS ) ? ( String ) this . mem . get ( USER_ADDRESS ) : null ) ;
}
2005-09-30 16:56:50 +02:00
public long getTimeUsed ( ) {
if ( this . mem . containsKey ( TIME_USED ) ) {
return Long . valueOf ( ( String ) this . mem . get ( TIME_USED ) ) . longValue ( ) ;
}
try {
this . setProperty ( TIME_USED , " 0 " ) ;
} catch ( IOException e ) {
e . printStackTrace ( ) ;
}
return 0 ;
}
2005-09-30 17:02:17 +02:00
public Long getTimeLimit ( ) {
return ( this . mem . containsKey ( TIME_LIMIT ) ? Long . valueOf ( ( String ) this . mem . get ( TIME_LIMIT ) ) : null ) ;
}
2005-09-30 17:41:01 +02:00
public long getTrafficSize ( ) {
if ( this . mem . containsKey ( TRAFFIC_SIZE ) ) {
return Long . valueOf ( ( String ) this . mem . get ( TRAFFIC_SIZE ) ) . longValue ( ) ;
}
try {
this . setProperty ( TRAFFIC_SIZE , " 0 " ) ;
} catch ( IOException e ) {
e . printStackTrace ( ) ;
}
return 0 ;
}
public Long getTrafficLimit ( ) {
return ( this . mem . containsKey ( TRAFFIC_LIMIT ) ? Long . valueOf ( ( String ) this . mem . get ( TRAFFIC_LIMIT ) ) : null ) ;
}
public long updateTrafficSize ( long responseSize ) {
if ( responseSize < 0 ) throw new IllegalArgumentException ( " responseSize must be greater or equal zero. " ) ;
long currentTrafficSize = getTrafficSize ( ) ;
long newTrafficSize = currentTrafficSize + responseSize ;
try {
this . setProperty ( TRAFFIC_SIZE , Long . toString ( newTrafficSize ) ) ;
} catch ( IOException e ) {
e . printStackTrace ( ) ;
}
return newTrafficSize ;
}
public Long getLastAccess ( ) {
return ( this . mem . containsKey ( LAST_ACCESS ) ? Long . valueOf ( ( String ) this . mem . get ( LAST_ACCESS ) ) : null ) ;
}
2005-09-30 16:56:50 +02:00
2005-10-10 12:21:25 +02:00
public boolean canSurf ( ) {
2005-10-12 12:58:21 +02:00
if ( this . getTimeLimit ( ) = = null | | this . getTimeLimit ( ) . longValue ( ) < = 0 | | ( this . updateLastAccess ( true ) < this . getTimeLimit ( ) . longValue ( ) ) ) //no timelimit or timelimit not reached
2005-10-10 12:21:25 +02:00
return true ;
else
return false ;
}
public long updateLastAccess ( boolean incrementTimeUsed ) {
return updateLastAccess ( System . currentTimeMillis ( ) , incrementTimeUsed ) ;
}
public long updateLastAccess ( long timeStamp , boolean incrementTimeUsed ) {
2005-09-30 16:56:50 +02:00
if ( timeStamp < 0 ) throw new IllegalArgumentException ( ) ;
Long lastAccess = this . getLastAccess ( ) ;
long oldTimeUsed = getTimeUsed ( ) ;
long newTimeUsed = oldTimeUsed ;
2005-10-10 12:21:25 +02:00
if ( incrementTimeUsed ) {
2005-10-14 12:53:50 +02:00
if ( ( lastAccess = = null ) | | ( ( lastAccess ! = null ) & & ( timeStamp - lastAccess . longValue ( ) > = 1000 * 60 ) ) ) { //1 minute
2005-10-10 16:25:18 +02:00
//this.mem.put(TIME_USED,Long.toString(newTimeUsed = ++oldTimeUsed));
newTimeUsed = + + oldTimeUsed ;
2005-10-10 15:06:03 +02:00
if ( lastAccess ! = null ) {
this . oldDate . setTime ( new Date ( lastAccess . longValue ( ) ) ) ;
this . newDate . setTime ( new Date ( System . currentTimeMillis ( ) ) ) ;
if (
this . oldDate . get ( Calendar . DAY_OF_MONTH ) ! = this . newDate . get ( Calendar . DAY_OF_MONTH ) | |
this . oldDate . get ( Calendar . MONTH ) ! = this . newDate . get ( Calendar . MONTH ) | |
this . oldDate . get ( Calendar . YEAR ) ! = this . newDate . get ( Calendar . YEAR )
) { //new Day, reset time
newTimeUsed = 0 ;
2005-10-10 15:38:13 +02:00
}
2005-10-10 15:06:03 +02:00
} else { //no access so far
newTimeUsed = 0 ;
}
this . mem . put ( TIME_USED , Long . toString ( newTimeUsed ) ) ;
2005-10-10 12:21:25 +02:00
this . mem . put ( LAST_ACCESS , Long . toString ( timeStamp ) ) ; //update Timestamp
2005-09-30 16:56:50 +02:00
}
2005-10-10 12:21:25 +02:00
} else {
this . mem . put ( LAST_ACCESS , Long . toString ( timeStamp ) ) ; //update Timestamp
}
2005-09-30 16:56:50 +02:00
try {
userDB . this . userTable . set ( getUserName ( ) , this . mem ) ;
} catch ( Exception e ) {
e . printStackTrace ( ) ;
}
return newTimeUsed ;
}
2005-09-30 12:28:49 +02:00
public String getMD5EncodedUserPwd ( ) {
return ( this . mem . containsKey ( MD5ENCODED_USERPWD_STRING ) ? ( String ) this . mem . get ( MD5ENCODED_USERPWD_STRING ) : null ) ;
}
public Map getProperties ( ) {
return this . mem ;
}
2005-09-30 16:56:50 +02:00
public void setProperty ( String propName , String newValue ) throws IOException {
this . mem . put ( propName , newValue ) ;
userDB . this . userTable . set ( getUserName ( ) , this . mem ) ;
}
public String getProperty ( String propName , String defaultValue ) {
return ( this . mem . containsKey ( propName ) ? ( String ) this . mem . get ( propName ) : defaultValue ) ;
}
2005-09-30 12:28:49 +02:00
public String toString ( ) {
StringBuffer str = new StringBuffer ( ) ;
str . append ( ( this . userName = = null ) ? " null " : this . userName )
2005-09-30 15:21:31 +02:00
. append ( " : " ) ;
2005-09-30 12:28:49 +02:00
if ( this . mem ! = null ) {
str . append ( this . mem . toString ( ) ) ;
}
return str . toString ( ) ;
}
2005-09-30 15:21:31 +02:00
}
2005-09-30 12:28:49 +02:00
2005-09-30 15:21:31 +02:00
public Iterator iterator ( boolean up ) {
// enumerates users
try {
return new userIterator ( up ) ;
} catch ( IOException e ) {
return new HashSet ( ) . iterator ( ) ;
}
2005-09-30 12:28:49 +02:00
}
2005-09-30 15:21:31 +02:00
public class userIterator implements Iterator {
// the iterator iterates all userNames
kelondroDyn . dynKeyIterator userIter ;
userDB . Entry nextEntry ;
public userIterator ( boolean up ) throws IOException {
this . userIter = userDB . this . userTable . keys ( up , false ) ;
this . nextEntry = null ;
}
public boolean hasNext ( ) {
try {
return this . userIter . hasNext ( ) ;
} catch ( kelondroException e ) {
resetDatabase ( ) ;
return false ;
}
}
public Object next ( ) {
try {
return getEntry ( ( String ) this . userIter . next ( ) ) ;
} catch ( kelondroException e ) {
resetDatabase ( ) ;
return null ;
}
}
public void remove ( ) {
if ( this . nextEntry ! = null ) {
try {
Object userName = this . nextEntry . getUserName ( ) ;
if ( userName ! = null ) removeEntry ( ( String ) userName ) ;
} catch ( kelondroException e ) {
resetDatabase ( ) ;
}
}
}
}
2005-09-30 12:28:49 +02:00
}