authlogger.go 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. package authlogger
  2. import (
  3. "encoding/json"
  4. "errors"
  5. "log"
  6. "net/http"
  7. "strconv"
  8. "strings"
  9. "time"
  10. "imuslab.com/arozos/mod/database"
  11. )
  12. /*
  13. AuthLogger
  14. Author: tobychui
  15. This module help log the login request and help the user to trace who is trying
  16. to break into their system.
  17. */
  18. type Logger struct {
  19. database *database.Database
  20. }
  21. type LoginRecord struct {
  22. Timestamp int64
  23. TargetUsername string
  24. LoginSucceed bool
  25. IpAddr string
  26. Port int
  27. }
  28. //New Logger create a new logger object
  29. func NewLogger() (*Logger, error) {
  30. db, err := database.NewDatabase("./system/auth/authlog.db", false)
  31. if err != nil {
  32. return nil, errors.New("*ERROR* Failed to create database for login tracking")
  33. }
  34. return &Logger{
  35. database: db,
  36. }, nil
  37. }
  38. //Log the current authentication to record, Require the request object and login status
  39. func (l *Logger) LogAuth(r *http.Request, loginStatus bool) error {
  40. username, _ := mv(r, "username", true)
  41. timestamp := time.Now().Unix()
  42. //Get the current month as the table name, create table if not exists
  43. current := time.Now().UTC()
  44. tableName := current.Format("Jan-2006")
  45. //Create table if not exists
  46. l.database.NewTable(tableName)
  47. //Split the remote address into ipaddr and port
  48. remoteAddrInfo := strings.Split(r.RemoteAddr, ":")
  49. port := -1
  50. if len(remoteAddrInfo) > 1 {
  51. port, _ = strconv.Atoi(remoteAddrInfo[1])
  52. }
  53. //Create the entry log struct
  54. thisRecord := LoginRecord{
  55. Timestamp: timestamp,
  56. TargetUsername: username,
  57. LoginSucceed: loginStatus,
  58. IpAddr: remoteAddrInfo[0],
  59. Port: port,
  60. }
  61. //Write the log to it
  62. entryKey := strconv.Itoa(int(time.Now().UnixNano()))
  63. err := l.database.Write(tableName, entryKey, thisRecord)
  64. if err != nil {
  65. log.Println("*ERROR* Failed to write authentication log. Is the storage fulled?")
  66. log.Println(err.Error())
  67. return err
  68. }
  69. return nil
  70. }
  71. //Close the database when system shutdown
  72. func (l *Logger) Close() {
  73. l.database.Close()
  74. }
  75. //List the total number of months recorded in the database
  76. func (l *Logger) ListSummary() []string {
  77. tableNames := []string{}
  78. l.database.Tables.Range(func(tableName, _ interface{}) bool {
  79. tableNames = append(tableNames, tableName.(string))
  80. return true
  81. })
  82. return tableNames
  83. }
  84. func (l *Logger) ListRecords(key string) ([]LoginRecord, error) {
  85. results := []LoginRecord{}
  86. if l.database.TableExists(key) {
  87. //Read all record from the database to login records
  88. entries, err := l.database.ListTable(key)
  89. if err != nil {
  90. return results, err
  91. }
  92. for _, keypairs := range entries {
  93. record := LoginRecord{}
  94. json.Unmarshal(keypairs[1], &record)
  95. results = append(results, record)
  96. }
  97. return results, nil
  98. } else {
  99. return results, errors.New("Table not exists")
  100. }
  101. }
  102. //Extract the address information from the request object, the first one is the remote address from the last hop,
  103. //and the 2nd one is the source address filled in by the client (not accurate)
  104. func getIpAddressFromRequest(r *http.Request) (string, []string) {
  105. lastHopAddress := r.RemoteAddr
  106. possibleSourceAddress := []string{}
  107. rawHeader := r.Header.Get("X-Forwarded-For")
  108. possibleSourceAddress = strings.Split(rawHeader, ", ")
  109. return lastHopAddress, possibleSourceAddress
  110. }